home *** CD-ROM | disk | FTP | other *** search
Wrap
/* ------------------------------------------------------------ */ /* HTTrack Website Copier, Offline Browser for Windows and Unix Copyright (C) Xavier Roche and other contributors This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Important notes: - We hereby ask people using this source NOT to use it in purpose of grabbing emails addresses, or collecting any other private information on persons. This would disgrace our work, and spoil the many hours we spent on it. Please visit our Website: http://www.httrack.com */ /* ------------------------------------------------------------ */ /* File: Main source */ /* Author: Xavier Roche */ /* ------------------------------------------------------------ */ #include "httrack.h" /* specific definitions */ #include "htsbase.h" #include "htsnet.h" #include "htsbauth.h" #include "htsmd5.h" #include "htsindex.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <fcntl.h> #include <ctype.h> /* END specific definitions */ /* HTML parsing */ #if HTS_ANALYSTE==2 char _hts_errmsg[1100]=""; int _hts_in_html_parsing=0; int _hts_in_html_done=0; // % done int _hts_in_html_poll=0; // parsing int _hts_setpause=0; httrackp* _hts_setopt=NULL; char** _hts_addurl=NULL; // int _hts_cancel=0; #endif char* structcheck_buff=NULL; int exit_xh; /* quick exit (fatal error or interrupt) */ /* debug */ #if DEBUG_SHOWTYPES char REG[32768]="\n"; #endif #if NSDEBUG int nsocDEBUG=0; #endif // #define _CLRSCR printf("\33[m\33[2J"); #define _GOTOXY(X,Y) printf("\33[" X ";" Y "f"); #if DEBUG_CHECKINT #define _CHECKINT_FAIL(a) printf("\n%s\n",a); fflush(stdout); exit(1); #define _CHECKINT(obj_ptr,message) \ if (obj_ptr) {\ if (( * ((char*) (obj_ptr)) != 0) || ( * ((char*) (((char*) (obj_ptr)) + sizeof(*(obj_ptr))-1)) != 0)) {\ char msg[1100];\ if (( * ((char*) (obj_ptr)) != 0) && ( * ((char*) (((char*) (obj_ptr)) + sizeof(*(obj_ptr))-1)) != 0))\ sprintf(msg,"* PANIC: Integrity error (structure crushed) in: %s",message);\ else if ( * ((char*) (obj_ptr)) != 0)\ sprintf(msg,"* PANIC: Integrity error (start of structure) in: %s",message);\ else\ sprintf(msg,"* PANIC: Integrity error (end of structure) in: %s",message);\ _CHECKINT_FAIL(msg);\ }\ } else {\ char msg[1100];\ sprintf(msg,"* PANIC: NULL pointer in: %s",message);\ _CHECKINT_FAIL(msg);\ } #endif #if DEBUG_HASH // longest hash chain? int longest_hash[3]={0,0,0},hashnumber=0; #endif // demande d'interaction avec le shell #if HTS_ANALYSTE==2 char HTbuff[1100]; #endif // DΘbut de httpmirror, routines annexes // version 1 pour httpmirror // flusher si on doit lire peu α peu le fichier #define test_flush if (opt.flush) { fflush(opt.log); fflush(opt.errlog); } // pour allΘger la syntaxe, des raccourcis sont crΘΘs #define urladr (liens[ptr]->adr) #define urlfil (liens[ptr]->fil) #define savename (liens[ptr]->sav) //#define level (liens[ptr]->depth) #define new_stat_bytes (HTS_STAT.HTS_TOTAL_RECV) // au cas o∙ nous devons quitter rapidement xhttpmirror (plus de mΘmoire, etc) // note: partir de liens_max.. vers 0.. sinon erreur de violation de mΘmoire: les liens suivants // ne sont plus α nous.. agh! [dur celui-lα] #if HTS_ANALYSTE #define HTMLCHECK_UNINIT hts_htmlcheck_end(); #else #define HTMLCHECK_UNINIT #endif #define XH_extuninit { \ int i; \ HTMLCHECK_UNINIT \ if (liens!=NULL) { \ for(i=lien_max-1;i>0;i--) { \ if (liens[i]) { \ if (liens[i]->firstblock==1) { \ freet(liens[i]); \ liens[i]=NULL; \ } \ } \ } \ liens=NULL; \ } \ if (filters[0]) { \ freet(filters[0]); filters[0]=NULL; \ } \ if (back) { \ int i; \ for(i=0;i<back_max;i++) { \ back_delete(back,i); \ } \ freet(back); back=NULL; \ } \ checkrobots_free(&robots);\ if (cache.use) { freet(cache.use); cache.use=NULL; } \ if (cache.dat) { fclose(cache.dat); cache.dat=NULL; } \ if (cache.ndx) { fclose(cache.ndx); cache.ndx=NULL; } \ if (cache.olddat) { fclose(cache.olddat); cache.olddat=NULL; } \ if (cache.lst) { fclose(cache.lst); cache.lst=NULL; } \ if (opt.log) fflush(opt.log); \ if (opt.errlog) fflush(opt.errlog);\ if (makestat_fp) { fclose(makestat_fp); makestat_fp=NULL; } \ if (maketrack_fp){ fclose(maketrack_fp); maketrack_fp=NULL; } \ if (opt.accept_cookie) cookie_save(opt.cookie,fconcat(opt.path_log,"cookies.txt")); \ if (makeindex_fp) { fclose(makeindex_fp); makeindex_fp=NULL; } \ if (cache_hash) { inthash_del(cache_hash,cache_hash_size); cache_hash=NULL; } \ } #define XH_uninit XH_extuninit if (r.adr) { freet(r.adr); r.adr=NULL; } // Enregistrement d'un lien: // on calcule la taille nΘcessaire: taille des 3 chaεnes α stocker (taille forcΘe paire, plus 2 octets de sΘcuritΘ) // puis on vΘrifie qu'on a assez de marge dans le buffer - sinon on en rΘalloue un autre // enfin on Θcrit α l'adresse courante du buffer, qu'on incrΘmente. on dΘcrΘmente la taille dispo d'autant ensuite // codebase: si non nul et si .class stockee on le note pour chemin primaire pour classes // FA,FS: former_adr et former_fil, lien original #define HTS_ALIGN 4 #if HTS_HASH #define liens_record_sav_len(A) #else #define liens_record_sav_len(A) (A)->sav_len=strlen((A)->sav) #endif #define liens_record(A,F,S,FA,FF) { \ int notecode=0; \ int adr_len=strlen(A),fil_len=strlen(F),sav_len=strlen(S),cod_len=0,former_adr_len=strlen(FA),former_fil_len=strlen(FF); \ if (former_adr_len>0) {\ former_adr_len=(former_adr_len/HTS_ALIGN)*HTS_ALIGN+HTS_ALIGN+4; \ former_fil_len=(former_fil_len/HTS_ALIGN)*HTS_ALIGN+HTS_ALIGN+4; \ } else former_adr_len=former_fil_len=0;\ if (strlen(F)>6) if (strnotempty(codebase)) if (strfield(F+strlen(F)-6,".class")) { notecode=1; \ cod_len=strlen(codebase); cod_len=(cod_len/HTS_ALIGN)*HTS_ALIGN+HTS_ALIGN+4; } \ adr_len=(adr_len/HTS_ALIGN)*HTS_ALIGN+HTS_ALIGN+4; fil_len=(fil_len/HTS_ALIGN)*HTS_ALIGN+HTS_ALIGN+4; sav_len=(sav_len/HTS_ALIGN)*HTS_ALIGN+HTS_ALIGN+4; \ if ((int) lien_size < (int) (adr_len+fil_len+sav_len+cod_len+former_adr_len+former_fil_len+sizeof(lien_url))) { \ lien_buffer=(char*) ((void*) calloct(add_tab_alloc,1)); \ lien_size=add_tab_alloc; \ if (lien_buffer!=NULL) { \ liens[lien_tot]=(lien_url*) (void*) lien_buffer; lien_buffer+=sizeof(lien_url); lien_size-=sizeof(lien_url); \ liens[lien_tot]->firstblock=1; \ } \ } else { \ liens[lien_tot]=(lien_url*) (void*) lien_buffer; lien_buffer+=sizeof(lien_url); lien_size-=sizeof(lien_url); \ liens[lien_tot]->firstblock=0; \ } \ if (liens[lien_tot]!=NULL) { \ liens[lien_tot]->adr=lien_buffer; lien_buffer+=adr_len; lien_size-=adr_len; \ liens[lien_tot]->fil=lien_buffer; lien_buffer+=fil_len; lien_size-=fil_len; \ liens[lien_tot]->sav=lien_buffer; lien_buffer+=sav_len; lien_size-=sav_len; \ liens[lien_tot]->cod=NULL; \ if (notecode) { liens[lien_tot]->cod=lien_buffer; lien_buffer+=cod_len; lien_size-=cod_len; strcpy(liens[lien_tot]->cod,codebase); } \ if (former_adr_len>0) {\ liens[lien_tot]->former_adr=lien_buffer; lien_buffer+=former_adr_len; lien_size-=former_adr_len; \ liens[lien_tot]->former_fil=lien_buffer; lien_buffer+=former_fil_len; lien_size-=former_fil_len; \ strcpy(liens[lien_tot]->former_adr,FA); \ strcpy(liens[lien_tot]->former_fil,FF); \ }\ strcpy(liens[lien_tot]->adr,A); \ strcpy(liens[lien_tot]->fil,F); \ strcpy(liens[lien_tot]->sav,S); \ liens_record_sav_len(liens[lien_tot]); \ hash_write(&hash,lien_tot); \ } \ } /* - abandonnΘ (simplifie) - // Ajouter α un lien EXISTANT deux champs former_adr et former_fil pour indiquer le nom d'un fichier avant un "move" // NOTE: si un alloc est fait ici il n'y aura pas de freet() α la fin, tant pis (firstbloc) #define liens_add_former(index,A,F) { \ int adr_len=strlen(A),fil_len=strlen(F); \ adr_len=(adr_len/HTS_ALIGN)*HTS_ALIGN+HTS_ALIGN+4; fil_len=(fil_len/HTS_ALIGN)*HTS_ALIGN+HTS_ALIGN+4; \ if ((int) lien_size < (int) (adr_len+fil_len)) { \ lien_buffer=(char*) calloct(add_tab_alloc,1); \ lien_size=add_tab_alloc; \ } \ if (lien_buffer!=NULL) { \ if (liens[lien_tot]!=NULL) { \ liens[lien_tot]->former_adr=lien_buffer; lien_buffer+=adr_len; lien_size-=adr_len; \ liens[lien_tot]->former_fil=lien_buffer; lien_buffer+=fil_len; lien_size-=fil_len; \ strcpy(liens[lien_tot]->former_adr,A); \ strcpy(liens[lien_tot]->former_fil,F); \ } \ } \ } */ #if 0 #define HT_ADD_ADR { \ fwrite(lastsaved,1,((int) adr)- ((int) lastsaved),fp); \ lastsaved=adr; } #define HT_ADD(A) fwrite(A,1,(int) strlen(A),fp); #define HT_ADD_START #define HT_ADD_END if (fp) { fclose(fp); fp=NULL; } #define HT_ADD_FOP { \ fp=filecreate(savename); \ if (fp==NULL) { \ if (opt.errlog) { \ fspc(opt.errlog,"error"); fprintf(opt.errlog,"Unable to create %s for %s%s"LF,savename,urladr,urlfil); \ test_flush; \ } \ freet(r.adr); r.adr=NULL; \ error=1; \ } \ } #else // version optimisΘe, qui permet de ne pas toucher aux html non modifiΘs (update) #define HT_ADD_CHK(A) if (((int) A+ht_len+1)>ht_size) { \ ht_size=A+ht_len+8192; \ ht_buff=(char*) realloct(ht_buff,ht_size); \ if (ht_buff==NULL) { \ printf("PANIC! : Not enough memory [%d]\n",__LINE__); \ XH_uninit; \ } \ } \ ht_len+=A; #define HT_ADD_ADR { int i,j=ht_len; HT_ADD_CHK(((int) adr)- ((int) lastsaved)) \ for(i=0;i<((int) adr)- ((int) lastsaved);i++) \ ht_buff[j+i]=lastsaved[i]; \ ht_buff[j+((int) adr)- ((int) lastsaved)]='\0'; \ lastsaved=adr; } #define HT_ADD(A) { HT_ADD_CHK(strlen(A)) strcat(ht_buff,A); } #define HT_ADD_START \ int ht_size=(int)(r.size*5)/4+8192; \ int ht_len=0; \ char* ht_buff=NULL; \ if ((opt.getmode & 1) && (ptr>0)) { \ ht_buff=(char*) malloct(ht_size); \ if (ht_buff==NULL) { \ printf("PANIC! : Not enough memory [%d]\n",__LINE__); \ XH_uninit; \ } \ ht_buff[0]='\0'; \ } #define HT_ADD_END { \ int ok=0;\ if (ht_buff) { \ int file_len=(int) strlen(ht_buff);\ char digest[32+2];\ digest[0]='\0';\ domd5mem(ht_buff,file_len,digest,1,0);\ if (fsize(antislash(savename))==file_len) { \ int mlen;\ char* mbuff;\ cache_readdata(&cache,"//[HTML-MD5]//",savename,&mbuff,&mlen);\ if (mlen) mbuff[mlen]='\0';\ if ((mlen == 32) && (strcmp(((mbuff!=NULL)?mbuff:""),digest)==0)) {\ ok=1;\ if ( (opt.debug>1) && (opt.log!=NULL) ) {\ fspc(opt.log,"debug"); fprintf(opt.log,"File not re-written (md5): %s"LF,savename);\ test_flush;\ }\ } else {\ FILE* fp2; \ int i=0; \ fp2=fopen(fconv(savename),"rb"); \ if (fp2) { \ ok=1; \ while((!feof(fp2)) && (ok)) { int c=fgetc(fp2); if (c!=EOF) { if ((char) c!=(char) ht_buff[i++]) ok=0; } } \ fclose(fp2); \ } \ } \ }\ if (!ok) { \ fp=filecreate(savename); \ if (fp) { \ if ((int)fwrite(ht_buff,1,file_len,fp) != file_len) { \ if (opt.errlog) { \ fspc(opt.errlog,"error"); fprintf(opt.errlog,"Unable to write HTML file %s"LF,savename);\ test_flush;\ }\ }\ fclose(fp); fp=NULL; \ if (strnotempty(r.lastmodified)) \ set_filetime_rfc822(savename,r.lastmodified); \ usercommand(0,NULL,antislash(savename)); \ } \ } else filenote(savename,NULL); \ if (cache.ndx)\ cache_writedata(cache.ndx,cache.dat,"//[HTML-MD5]//",savename,digest,(int)strlen(digest));\ } \ freet(ht_buff); ht_buff=NULL; \ } #define HT_ADD_FOP #endif // libΘrer filters[0] pour insΘrer un ΘlΘment dans filters[0] #define HT_INSERT_FILTERS0 {\ int i;\ if (filptr>0) {\ for(i=filptr-1;i>=0;i--) {\ strcpy(filters[i+1],filters[i]);\ }\ }\ strcpy(filters[0],"");\ filptr++;\ filptr=minimum(filptr,filter_max);\ } // DΘbut de httpmirror, robot // url1 peut Ωtre multiple int httpmirror(char* url1,httrackp opt) { char* primary=NULL; // premiΦre page, contenant les liens α scanner int lien_tot=0; // nombre de liens pour le moment lien_url** liens=NULL; // les pointeurs sur les liens hash_struct hash; // systΦme de hachage, accΘlΦre la recherche dans les liens t_cookie cookie; // gestion des cookies int lien_max=0; int lien_size=0; // octets restants dans buffer liens dispo char* lien_buffer=NULL; // buffer liens actuel int add_tab_alloc=256000; // +256K de liens α chaque fois //char* tab_alloc=NULL; int ptr; // pointeur actuel sur les liens // int numero_passe=0; // deux passes pour html puis images int back_max=0; // fichiers qui peuvent Ωtre en local lien_back* back=NULL; // backing en local htsblk r; // retour de certaines fonctions double lastime=0; // pour affichage infos de tmp en tmp // pour les stats, nombre de fichiers & octets Θcrits LLint stat_fragment=0; // pour la fragmentation //double istat_timestart; // dΘpart pour calcul instantannΘ // double last_info_shell=0; int info_shell=0; // note: α amΘliorer // ** char* filters[usd_max]; int filter_max=0; int filptr=0; // int makeindex_done=0; // lorsque l'index sera fait FILE* makeindex_fp=NULL; int makeindex_links=0; char makeindex_firstlink[HTS_URLMAXSIZE*2]; // statistiques (mode #Z) FILE* makestat_fp=NULL; // fichier de stats taux transfert FILE* maketrack_fp=NULL; // idem pour le tracking double makestat_time=0; // attente (secondes) LLint makestat_total=0; // repΦre du nombre d'octets transfΘrΘs depuis denriΦre stat int makestat_lnk=0; // idem, pour le nombre de liens // char codebase[HTS_URLMAXSIZE*2]; // base pour applet java char base[HTS_URLMAXSIZE*2]; // base pour les autres fichiers // cache_back cache; robots_wizard robots; // gestion robots.txt hash_chain** cache_hash=NULL; int cache_hash_size=0; // codebase[0]='\0'; base[0]='\0'; // cookie.auth.next=NULL; cookie.auth.auth[0]=cookie.auth.prefix[0]='\0'; // // noter heure actuelle de dΘpart en secondes bzero((char *)&HTS_STAT, sizeof(HTS_STAT)); HTS_STAT.stat_timestart=time_local(); //istat_timestart=stat_timestart; HTS_STAT.imstat_timestart=mtime_local(); /* reset stats */ new_stat_bytes=0; HTS_STAT.istat_bytes=0; if (opt.aff_progress) lastime=HTS_STAT.stat_timestart; if (opt.shell) { last_info_shell=HTS_STAT.stat_timestart; } if ((opt.makestat) || (opt.maketrack)){ makestat_time=HTS_STAT.stat_timestart; } // initialiser cookie if (opt.accept_cookie) { opt.cookie=&cookie; cookie.max_len=30000; // max len strcpy(cookie.data,""); // Charger cookies.txt par dΘfaut ou cookies.txt du miroir if (fexist(fconcat(opt.path_log,"cookies.txt"))) cookie_load(opt.cookie,opt.path_log,"cookies.txt"); else if (fexist("cookies.txt")) cookie_load(opt.cookie,"","cookies.txt"); } else opt.cookie=NULL; // initialiser exit_xh exit_xh=0; // sortir prΘmaturΘment (var globale) // initialiser usercommand usercommand(opt.sys_com_exec,opt.sys_com,""); // Initialiser indexation if (opt.kindex) index_init(opt.path_html); // effacer bloc cache bzero((char *)&cache, sizeof(cache_back)); cache.type=opt.cache; // cache? cache.errlog=opt.errlog; // err log? cache.ptr_ant=cache.ptr_last=0; // pointeur pour anticiper // initialiser hash cache if (!cache_hash_size) cache_hash_size=HTS_HASH_SIZE; cache_hash=(hash_chain**)calloc(cache_hash_size,sizeof(hash_chain*)); if (cache_hash==NULL) { printf("PANIC! : Not enough memory [%d]\n",__LINE__); filters[0]=NULL; back_max=0; // uniquement a cause du warning de XH_extuninit XH_extuninit; return 0; } inthash_init(cache_hash,cache_hash_size); cache.hash=(void**)cache_hash; /* copy backcache hash */ cache.hash_size=cache_hash_size; // initialiser cache DNS _hts_lockdns(-999); // robots.txt strcpy(robots.adr,"!"); // dummy robots.token[0]='\0'; robots.next=NULL; // suivant // effacer filters filter_max=maximum(opt.maxfilter,128); filters[0]=(char*) malloct((filter_max+1)*(HTS_URLMAXSIZE*2)); if (filters[0]==NULL) { printf("PANIC! : Not enough memory [%d]\n",__LINE__); back_max=0; // uniquement a cause du warning de XH_extuninit XH_extuninit; return 0; } else { int i; for(i=0;i<=filter_max;i++) { // PLUS UN (sΘcuritΘ) filters[i]=filters[0]+i*(HTS_URLMAXSIZE*2); filters[i][0]='\0'; } } opt.filters.filptr=&filptr; opt.filters.filter_max=&filter_max; opt.filters.filters=filters; // tableau de pointeurs sur les liens lien_max=maximum(opt.maxlink,32); liens=(lien_url**) malloct(lien_max*sizeof(lien_url*)); // tableau de pointeurs sur les liens if (liens==NULL) { printf("PANIC! : Not enough memory [%d]\n",__LINE__); //XH_uninit; return 0; } else { int i; for(i=0;i<lien_max;i++) { liens[i]=NULL; } } // initialiser ptr et lien_tot ptr=0; lien_tot=0; #if HTS_HASH // initialiser hachage { int i; for(i=0;i<HTS_HASH_SIZE;i++) hash.hash[0][i]=hash.hash[1][i]=hash.hash[2][i] = -1; // pas d'entrΘes hash.liens = liens; hash.max_lien=0; } #endif // copier adresse(s) dans liste des adresses { char *a=url1; int primary_len=8192; if (strnotempty(opt.filelist)) { primary_len+=max(0,fsize(opt.filelist)*2); } primary_len+=strlen(url1)*2; // crΘation de la premiΦre page, qui contient les liens de base α scanner // c'est plus propre et plus logique que d'entrer α la main les liens dans la pile // on bΘnΘficie ainsi des vΘrifications et des tests du robot pour les liens "primaires" primary=(char*) malloct(primary_len); if (primary) { primary[0]='\0'; } else { printf("PANIC! : Not enough memory [%d]\n",__LINE__); back_max=0; // uniquement a cause du warning de XH_extuninit XH_extuninit; return 0; } while(*a) { int i; int joker=0; // vΘrifier qu'il n'y a pas de * dans l'url if (*a=='+') joker=1; else if (*a=='-') joker=1; /* NON, certaines URL ont des * (!) else { int i=0; while((a[i]!=0) && (a[i]!=' ')) if (a[i++]=='*') joker=1; } */ if (joker) { // joker ou filters //char* p; char tempo[HTS_URLMAXSIZE*2]; int type; int plus=0; // noter joker (dans b) if (*a=='+') { // champ + type=1; plus=1; a++; } else if (*a=='-') { // champ forbidden[] type=0; a++; } else { // champ + avec joker sans doute type=1; } // recopier prochaine chaine (+ ou -) i=0; while((*a!=0) && (*a!=' ')) { tempo[i++]=*a; a++; } tempo[i++]='\0'; while(*a==' ') { a++; } // sauter les + sans rien aprΦs.. if (strnotempty(tempo)) { if ((plus==0) && (type==1)) { // implicite: *www.edf.fr par exemple if (tempo[strlen(tempo)-1]!='*') { strcat(tempo,"*"); // ajouter un * } } if (type) strcpy(filters[filptr],"+"); else strcpy(filters[filptr],"-"); if (strncmp(tempo,"http://",7)==0) strcat(filters[filptr],tempo+7); // ignorer http:// else if (strncmp(tempo,"ftp://",6)==0) strcat(filters[filptr],tempo+6); // ignorer ftp:// else strcat(filters[filptr],tempo); filptr++; } } else { // adresse normale char url[HTS_URLMAXSIZE*2]; // prochaine adresse i=0; while((*a!=0) && (*a!=' ')) { url[i++]=*a; a++; } while(*a==' ') { a++; } url[i++]='\0'; strcat(primary,"<PRIMARY=\""); if (strstr(url,":/")==NULL) strcat(primary,"http://"); strcat(primary,url); strcat(primary,"\">\n"); } } // while /* intΘgrer liste de fichiers */ if (strnotempty(opt.filelist)) { FILE* fp=fopen(opt.filelist,"rb"); if (fp) { int n=0; char line[512]; while(!feof(fp)) { linput(fp,line,500); if (strnotempty(line)) { n++; strcat(primary,"<PRIMARY=\""); if (strstr(line,":/")==NULL) strcat(primary,"http://"); strcat(primary,line); strcat(primary,"\">\n"); } } fclose(fp); if (opt.log!=NULL) { fspc(opt.log,"info"); fprintf(opt.log,"%d links added from %s"LF,n,opt.filelist); test_flush; } } else { if (opt.errlog!=NULL) { fspc(opt.errlog,"error"); fprintf(opt.errlog,"Could not include URL list: %s"LF,opt.filelist); test_flush; } } } // lien primaire liens_record("primary","/primary","primary.html","",""); if (liens[lien_tot]==NULL) { // erreur, pas de place rΘservΘe printf("PANIC! : Not enough memory [%d]\n",__LINE__); if (opt.errlog) { fprintf(opt.errlog,"Not enough memory, can not re-allocate %d bytes"LF,(add_tab_alloc+1)*sizeof(lien_url)); test_flush; } back_max=0; // uniquement a cause du warning de XH_extuninit XH_extuninit; // dΘsallocation mΘmoire & buffers return 0; } liens[lien_tot]->testmode=0; // pas mode test liens[lien_tot]->link_import=0; // pas mode import liens[lien_tot]->depth=opt.depth+1; // lien de prioritΘ maximale liens[lien_tot]->pass2=0; // 1Φre passe liens[lien_tot]->retry=opt.retry; // lien de prioritΘ maximale liens[lien_tot]->premier=lien_tot; // premier lien, objet-pΦre=objet liens[lien_tot]->precedent=lien_tot; // lien prΘcΘdent lien_tot++; // Initialiser cache cache_init(&cache,&opt); } #if BDEBUG==3 { int i; for(i=0;i<lien_tot;i++) { printf("%d>%s%s as %s\n",i,liens[i]->adr,liens[i]->fil,liens[i]->sav); } for(i=0;i<filptr;i++) { printf("%d>filters=%s\n",i,filters[i]); } } #endif // backing //soc_max=opt.maxsoc; if (opt.maxsoc>0) { #if BDEBUG==2 _CLRSCR; #endif // Nombre de fichiers HTML pouvant Ωtre prΘsents en mΘmoire de maniΦre simultannΘe // On prΘvoit large: les fichiers HTML ne prennent que peu de place en mΘmoire, et les // fichiers non html sont sauvΘs en direct sur disque. // --> 1024 entrΘes + 32 entrΘes par socket en supplΘment back_max=opt.maxsoc*32+1024; //back_max=opt.maxsoc*8+32; back=(lien_back*) calloct((back_max+1),sizeof(lien_back)); if (back==NULL) { if (opt.errlog) fprintf(opt.errlog,"Not enough memory, can not allocate %d bytes"LF,(opt.maxsoc+1)*sizeof(lien_back)); return 0; } else { // copier buffer-location & effacer int i; for(i=0;i<back_max;i++){ back[i].r.location=back[i].location_buffer; back[i].status=-1; back[i].r.soc=INVALID_SOCKET; } } } // flush test_flush; // statistiques if (opt.makestat) { makestat_fp=fopen(fconcat(opt.path_log,"hts-stats.txt"),"wb"); if (makestat_fp != NULL) { fprintf(makestat_fp,"HTTrack statistics report, every minutes"LF LF); } } // tracking -- dΘbuggage if (opt.maketrack) { maketrack_fp=fopen(fconcat(opt.path_log,"hts-track.txt"),"wb"); if (maketrack_fp != NULL) { fprintf(maketrack_fp,"HTTrack tracking report, every minutes"LF LF); } } // on n'a pas de liens!! (exemple: httrack www.* impossible sans dΘpart..) if (lien_tot<=0) { if (opt.errlog) { fprintf(opt.errlog,"Error! You MUST specify at least one complete URL, and not only wildcards!"LF); } } // attendre une certaine heure.. if (opt.waittime>0) { int rollover=0; int ok=0; { double tl=0; time_t tt; struct tm* A; tt=time(NULL); A=localtime(&tt); tl+=A->tm_sec; tl+=A->tm_min*60; tl+=A->tm_hour*60*60; if (tl>opt.waittime) // attendre minuit rollover=1; } // attendre.. do { double tl=0; time_t tt; struct tm* A; tt=time(NULL); A=localtime(&tt); tl+=A->tm_sec; tl+=A->tm_min*60; tl+=A->tm_hour*60*60; if (rollover) { if (tl<=opt.waittime) rollover=0; // attendre heure } else { if (tl>opt.waittime) ok=1; // ok! } #if HTS_ANALYSTE { int r; if (rollover) r=hts_htmlcheck_loop(back,back_max,0,0,lien_tot,0,0,(int) (opt.waittime-tl+24*3600),-1,-1,-1,-1,-1,-1); else r=hts_htmlcheck_loop(back,back_max,0,0,lien_tot,0,0,(int) (opt.waittime-tl),-1,-1,-1,-1,-1,-1); if (!r) { exit_xh=1; // exit requested ok=1; } else Sleep(100); } #endif } while(!ok); // note: recopie de plus haut // noter heure actuelle de dΘpart en secondes HTS_STAT.stat_timestart=time_local(); if (opt.aff_progress) lastime=HTS_STAT.stat_timestart; if (opt.shell) { last_info_shell=HTS_STAT.stat_timestart; } if ((opt.makestat) || (opt.maketrack)){ makestat_time=HTS_STAT.stat_timestart; } } #if HTS_ANALYSTE /* if (!hts_htmlcheck_loop(back,back_max,0,0,lien_tot,0,0,0,-1,-1,-1,-1,-1)) { XH_extuninit; return 1; } Sleep(100); */ if (!hts_htmlcheck_start()) { XH_extuninit; return 1; } #endif // ------------------------------------------------------------ // ------------------------------------------------------------ // Boucle gΘnΘrale de parcours des liens // ------------------------------------------------------------ do { int error=0; // si error alors sauter int store_errpage=0; // c'est une erreur mais on enregistre le html char loc[HTS_URLMAXSIZE*2]; // adresse de relocation // Ici on charge le fichier (html, gif..) en mΘmoire // Les HTMLs sont traitΘs (si leur prioritΘ est suffisante) // effacer r bzero((char *)&r, sizeof(htsblk)); r.soc=INVALID_SOCKET; r.location=loc; // en cas d'erreur 3xx (moved) // recopier proxy bcopy((char*) &opt.proxy,(char*) &(r.req.proxy), sizeof(opt.proxy)); // et user-agent strcpy(r.req.user_agent,opt.user_agent); r.req.user_agent_send=opt.user_agent_send; if (!error) { // Skip empty/invalid/done in background if (liens[ptr]) { while ( (liens[ptr]) && ( ( ((urladr != NULL)?(urladr):(" "))[0]=='!') || ( ((urlfil != NULL)?(urlfil):(" "))[0]=='\0') || ( (liens[ptr]->pass2 == -1) ) ) ) { // sauter si lien annulΘ (ou fil vide) if ((opt.debug>1) && (opt.log!=NULL)) { fspc(opt.log,"debug"); fprintf(opt.log,"link #%d seems ready, skipping: %s%s.."LF,ptr,((urladr != NULL)?(urladr):(" ")),((urlfil != NULL)?(urlfil):(" "))); test_flush; } ptr++; } } if (liens[ptr]) { // on a qq chose α rΘcupΘrer? if ( (opt.debug>1) && (opt.log!=NULL) ) { fspc(opt.log,"debug"); fprintf(opt.log,"Wait get: %s%s"LF,urladr,urlfil); test_flush; #if DEBUG_ROBOTS if (strcmp(urlfil,"/robots.txt") == 0) { printf("robots.txt detected\n"); } #endif } // ------------------------------------------------------------ // DEBUT --RECUPERATION LIEN--- if (ptr==0) { // premier lien α parcourir: lien primaire construit avant r.adr=primary; primary=NULL; r.statuscode=200; r.size=strlen(r.adr); r.soc=INVALID_SOCKET; strcpy(r.contenttype,"text/html"); /*} else if (opt.maxsoc<=0) { // fichiers 1 α 1 en attente (pas de backing) // charger le fichier en mΘmoire tout bΩtement r=xhttpget(urladr,urlfil); // */ } else { // backing, multiples sockets // int b; int n; #if BDEBUG==1 printf("\nBack test..\n"); #endif if (opt.fragment>0) { if ((HTS_STAT.stat_bytes-stat_fragment) > opt.fragment) { while (back_nsoc(back,back_max)>0) { // attendre fin des transferts back_wait(back,back_max,&opt,&cache,HTS_STAT.stat_timestart); Sleep(100); } // On dΘsalloue le buffer d'enregistrement des chemins crΘΘe, au cas o∙ pendant la pause // l'utilisateur ferait un rm -r aprΦs avoir effectuΘ un tar if (structcheck_buff) { freet(structcheck_buff); structcheck_buff=NULL; } { FILE* fp = fopen(fconcat(opt.path_log,"hts-paused.lock"),"wb"); if (fp) { fspc(fp,"info"); // dater fprintf(fp,"Pause\nHTTrack is paused after retreiving "LLintP" bytes\nDelete this file to continue the mirror...\n\n",HTS_STAT.stat_bytes); fclose(fp); } } stat_fragment=HTS_STAT.stat_bytes; while (fexist(fconcat(opt.path_log,"hts-paused.lock"))) { //back_wait(back,back_max,&opt,&cache,HTS_STAT.stat_timestart); inutile!! (plus de sockets actives) Sleep(1000); } } } #if HTS_ANALYSTE==2 // changement dans les prΘfΘrences if (_hts_setopt) { copy_htsopt(_hts_setopt,&opt); // copier au besoin _hts_setopt=NULL; // effacer callback } if (_hts_addurl) { char add_adr[HTS_URLMAXSIZE*2]; char add_fil[HTS_URLMAXSIZE*2]; while(*_hts_addurl) { char add_url[HTS_URLMAXSIZE*2]; add_adr[0]=add_fil[0]=add_url[0]='\0'; if (strstr(*_hts_addurl,"://")==NULL) strcpy(add_url,"http://"); // ajouter http:// strcat(add_url,*_hts_addurl); if (ident_url(add_url,add_adr,add_fil)>=0) { // ----Ajout---- // noter NOUVEAU lien char add_sav[HTS_URLMAXSIZE*2]; // calculer lien et Θventuellement modifier addresse/fichier if (url_savename(add_adr,add_fil,add_sav,NULL,NULL,NULL,NULL,&opt,liens,lien_tot,back,back_max,&cache,&hash,ptr,numero_passe)!=-1) { if (hash_read(&hash,add_sav,"",0)<0) { // n'existe pas dΘja // enregistrer lien (MACRO) liens_record(add_adr,add_fil,add_sav,"",""); if (liens[lien_tot]!=NULL) { // OK, pas d'erreur liens[lien_tot]->testmode=0; // mode test? liens[lien_tot]->link_import=0; // mode normal liens[lien_tot]->depth=opt.depth; liens[lien_tot]->pass2=max(0,numero_passe); liens[lien_tot]->retry=opt.retry; liens[lien_tot]->premier=lien_tot; liens[lien_tot]->precedent=lien_tot; lien_tot++; // if ((opt.debug>0) && (opt.log!=NULL)) { fspc(opt.log,"info"); fprintf(opt.log,"Link added by user: %s%s"LF,add_adr,add_fil); test_flush; } // } else { // oups erreur, plus de mΘmoire!! printf("PANIC! : Not enough memory [%d]\n",__LINE__); if (opt.errlog) { fprintf(opt.errlog,"Not enough memory, can not re-allocate %d bytes"LF,(add_tab_alloc+1)*sizeof(lien_url)); test_flush; } //if (opt.getmode & 1) { if (fp) { fclose(fp); fp=NULL; } } XH_uninit; // dΘsallocation mΘmoire & buffers return 0; } } else { if ( (opt.debug>0) && (opt.errlog!=NULL) ) { fspc(opt.errlog,"warning"); fprintf(opt.errlog,"Existing link %s not added after user request"LF,add_adr,add_fil); test_flush; } } } } else { if (opt.errlog) { fspc(opt.errlog,"error"); fprintf(opt.errlog,"Error during URL decoding for %s%s"LF,add_url); test_flush; } } // ----Fin Ajout---- _hts_addurl++; // suivante } _hts_addurl=NULL; // libΘrer _hts_addurl } // si une pause a ΘtΘ demandΘe if (_hts_setpause) { // index du lien actuel int b=back_index(back,back_max,urladr,urlfil,savename); if (b<0) b=0; // forcer pour les stats while(_hts_setpause) { // on fait la pause.. LLint nb; int nbk; back_wait(back,back_max,&opt,&cache,HTS_STAT.stat_timestart); nb=back_transfered(HTS_STAT.stat_bytes,back,back_max); nbk=backlinks_done(liens,lien_tot,ptr); engine_stats(); if (!hts_htmlcheck_loop(back,back_max,b,ptr,lien_tot,nb,new_stat_bytes,(int) (time_local()-HTS_STAT.stat_timestart),back_nsoc(back,back_max),HTS_STAT.stat_files,HTS_STAT.stat_updated_files,fspc(NULL,"error"),(int)HTS_STAT.rate,nbk )) { if (opt.errlog) { fspc(opt.errlog,"info"); fprintf(opt.errlog,"Exit requested by shell or user"LF); test_flush; } exit_xh=1; // exit requested XH_uninit; return 0; } if (back_nsoc(back,back_max)==0) Sleep(250); // tite pause } } #endif // si le fichier n'est pas en backing, le mettre.. if (!back_exist(back,back_max,urladr,urlfil,savename)) { #if BDEBUG==1 printf("crash backing: %s%s\n",liens[ptr]->adr,liens[ptr]->fil); #endif if (back_add(back,back_max,&opt,&cache,urladr,urlfil,savename,liens[liens[ptr]->precedent]->adr,liens[liens[ptr]->precedent]->fil,liens[ptr]->testmode,&liens[ptr]->pass2)==-1) { printf("PANIC! : Crash adding error, unexpected error found.. [%d]\n",__LINE__); #if BDEBUG==1 printf("error while crash adding\n"); #endif if (opt.errlog) { fspc(opt.errlog,"error"); fprintf(opt.errlog,"Unexpected backing error for %s%s"LF,urladr,urlfil); test_flush; } } } #if BDEBUG==1 printf("test number of socks\n"); #endif // ajouter autant de socket qu'on peut ajouter n=opt.maxsoc-back_nsoc(back,back_max); #if BDEBUG==1 printf("%d sockets available for backing\n",n); #endif #if HTS_ANALYSTE==2 if ((n>0) && (!_hts_setpause)) { // si sockets libre et pas en pause, ajouter #else if (n>0) { // si sockets libre #endif // remplir autant que l'on peut le cache (backing) back_fillmax(back,back_max,&opt,&cache,liens,ptr,numero_passe,lien_tot); } // index du lien actuel /* b=back_index(back,back_max,urladr,urlfil,savename); if (b>=0) */ { // ------------------------------------------------------------ // attendre que le fichier actuel soit prΩt - BOUCLE D'ATTENTE do { // index du lien actuel b=back_index(back,back_max,urladr,urlfil,savename); #if BDEBUG==1 printf("back index %d, waiting\n",b); #endif // Continue to the loop if link still present if (b<0) continue; // Receive data if (back[b].status>0) back_wait(back,back_max,&opt,&cache,HTS_STAT.stat_timestart); // Continue to the loop if link still present b=back_index(back,back_max,urladr,urlfil,savename); if (b<0) continue; // And fill the backing stack if (back[b].status>0) back_fillmax(back,back_max,&opt,&cache,liens,ptr,numero_passe,lien_tot); // Continue to the loop if link still present b=back_index(back,back_max,urladr,urlfil,savename); if (b<0) continue; // autres occupations de HTTrack: statistiques, boucle d'attente, etc. if ((opt.makestat) || (opt.maketrack)) { double l=time_local(); if ((int) (l-makestat_time) >= 60) { if (makestat_fp != NULL) { fspc(makestat_fp,"info"); fprintf(makestat_fp,"Rate= %d (/"LLintP") \11NewLinks= %d (/%d)"LF,(int) ((new_stat_bytes-makestat_total)/(l-makestat_time)), new_stat_bytes,(int) lien_tot-makestat_lnk,(int) lien_tot); fflush(makestat_fp); makestat_total=new_stat_bytes; makestat_lnk=lien_tot; } if (maketrack_fp!=NULL) { int i; fspc(maketrack_fp,"info"); fprintf(maketrack_fp,LF); for(i=0;i<back_max;i++) { back_info(back,i,3,maketrack_fp); } fprintf(maketrack_fp,LF); } makestat_time=l; } } #if HTS_ANALYSTE==2 { LLint nb; int nbk; int i; { char* s=hts_cancel_file(""); if (strnotempty(s)) { // fichier α canceller for(i=0;i<back_max;i++) { if ((back[i].status>0)) { if (strcmp(back[i].url_sav,s)==0) { // ok trouvΘ if (back[i].status != 1000) { #if HTS_DEBUG_CLOSESOCK DEBUG_W("user cancel: deletehttp\n"); #endif if (back[i].r.soc!=INVALID_SOCKET) deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET; back[i].r.statuscode=-1; strcpy(back[i].r.msg,"Cancelled by User"); back[i].status=0; // terminΘ } else // cancel ftp.. flag α 1 back[i].stop_ftp = 1; } } } s[0]='\0'; } } engine_stats(); nb=back_transfered(HTS_STAT.stat_bytes,back,back_max); nbk=backlinks_done(liens,lien_tot,ptr); if (!hts_htmlcheck_loop(back,back_max,b,ptr,lien_tot,nb,new_stat_bytes,(int) (time_local()-HTS_STAT.stat_timestart),back_nsoc(back,back_max),HTS_STAT.stat_files,HTS_STAT.stat_updated_files,fspc(NULL,"error"),(int)HTS_STAT.rate,nbk )) { if (opt.errlog) { fspc(opt.errlog,"info"); fprintf(opt.errlog,"Exit requested by shell or user"LF); test_flush; } exit_xh=1; // exit requested XH_uninit; return 0; } } #endif #if HTS_POLL if ((opt.shell) || (opt.keyboard)) { int rcvd=0; double tl; info_shell=1; // Traitement Θventuel des requΦtes stdin etc. while (check_stdin()) { // donnΘes disponibles char com[256]; com[0]='\0'; if (!rcvd) rcvd=1; linput(stdin,com,256); if (strnotempty(com)) { if (strlen(com)<=2) { switch(*com) { case '?': { // Status? if (back[b].status>0) printf("WAIT\n"); else printf("READY\n"); } break; case 'f': { // Fichier en attente? if (back[b].status>0) printf("WAIT %s\n",back[b].url_fil); else printf("READY %s\n",back[b].url_fil); } break; case 'A': case 'F': { // filters int i; for(i=0;i<filptr;i++) { printf("%s ",filters[i]); } printf("\n"); } break; case '#': { // Afficher statistique sur le nombre de liens, etc switch(*(com+1)) { case 'l': printf("%d\n",lien_tot); break; // nombre de liens enregistrΘs case 's': printf("%d\n",back_nsoc(back,back_max)); break; // nombre de sockets case 'r': printf("%d\n",(int) (new_stat_bytes/(time_local()-HTS_STAT.stat_timestart))); break; // taux de transfert } } break; case 'K': if (*(com+1)=='!') { // Kill XH_uninit; return -1; } break; case 'X': if (*(com+1)=='!') { // exit exit_xh=1; } break; case 'I': if (*(com+1)=='+') info_shell=1; else info_shell=0; break; } io_flush; } else if (*com=='@') { printf("%s\n",com+1); io_flush; } } } // while tl=time_local(); // gΘnΘrer un message d'infos sur l'Θtat actuel if (opt.shell) { // si shell if ((tl-last_info_shell)>0) { // toute les 1 sec FILE* fp=stdout; int a=0; last_info_shell=tl; if (fexist(fconcat(opt.path_log,"hts-autopsy"))) { // dΘbuggage: teste si le robot est vivant // (oui je sais un robot vivant.. mais bon.. il a le droit de vivre lui aussi) // (libΘrons les robots esclaves de l'internet!) remove(fconcat(opt.path_log,"hts-autopsy")); fp=fopen(fconcat(opt.path_log,"hts-isalive"),"wb"); a=1; } if ((info_shell) || a) { int i,j; fprintf(fp,"TIME %d"LF,(int) (tl-HTS_STAT.stat_timestart)); fprintf(fp,"TOTAL %d"LF,(int) HTS_STAT.stat_bytes); fprintf(fp,"RATE %d"LF,(int) (new_stat_bytes/(tl-HTS_STAT.stat_timestart))); fprintf(fp,"SOCKET %d"LF,back_nsoc(back,back_max)); fprintf(fp,"LINK %d"LF,lien_tot); { LLint mem=0; for(i=0;i<back_max;i++) if (back[i].r.adr!=NULL) mem+=back[i].r.size; fprintf(fp,"INMEM "LLintP""LF,mem); } for(j=0;j<2;j++) { // passes pour ready et wait for(i=0;i<back_max;i++) { back_info(back,i,j+1,stdout); // maketrack_fp a la place de stdout ?? // ** } } fprintf(fp,LF); if (a) fclose(fp); io_flush; } } } // si shell } // si shell ou keyboard (option) // #endif } while((b>=0) && (back[max(b,0)].status>0)); // If link not found on the stack, it's because it has already been downloaded // in background // Then, skip it and go to the next one if (b<0) { if ((opt.debug>1) && (opt.log!=NULL)) { fspc(opt.log,"debug"); fprintf(opt.log,"link #%d is ready, no more on the stack, skipping: %s%s.."LF,ptr,urladr,urlfil); test_flush; } // prochain lien ptr++; // Jump to 'continue' // This is one of the very very rare cases where goto // is acceptable // A supplemental flag and if() { } would be really messy goto jump_if_done; } #if HTS_ANALYSTE #else if (!opt.quiet) { // petite animation if (!opt.verbosedisplay) { static int roll=0; roll=(roll+1)%4; printf("%c\x0d",("/-\\|")[roll]); fflush(stdout); } else { if (back[b].r.statuscode==200) printf("%d/%d: %s%s ("LLintP" bytes) - OK\33[K\r",ptr,lien_tot,back[b].url_adr,back[b].url_fil,back[b].r.size); else printf("%d/%d: %s%s ("LLintP" bytes) - %d\33[K\r",ptr,lien_tot,back[b].url_adr,back[b].url_fil,back[b].r.size,back[b].r.statuscode); fflush(stdout); } } #endif // ------------------------------------------------------------ // VΘrificateur d'intΘgritΘ #if DEBUG_CHECKINT _CHECKINT(&back[b],"Retour de back_wait, aprΦs le while") { int i; for(i=0;i<back_max;i++) { char si[256]; sprintf(si,"Test global aprΦs back_wait, index %d",i); _CHECKINT(&back[i],si) } } #endif // copier structure rΘponse htsblk bcopy((char*) &(back[b].r), (char*) &r, sizeof(htsblk)); r.location=loc; // ne PAS copier location!! adresse, pas de buffer if (back[b].r.location) strcpy(r.location,back[b].r.location); back[b].r.adr=NULL; // ne pas faire de desalloc ensuite // libΘrer emplacement backing back_delete(back,b); // progression if (opt.aff_progress) { double tl=time_local(); if ((tl-lastime)>0) { char s[32]; int i=0; lastime=tl; _CLRSCR; _GOTOXY("1","1"); printf("Rate=%d B/sec\n",(int) (new_stat_bytes/(tl-HTS_STAT.stat_timestart))); while(i<minimum(back_max,99)) { // ** if (back[i].status>=0) { // loading.. s[0]='\0'; if (strlen(back[i].url_fil)>16) strcat(s,back[i].url_fil+strlen(back[i].url_fil)-16); else strncat(s,back[i].url_fil,16); printf("%s : ",s); printf("["); if (back[i].r.totalsize>0) { int p; int j; p=(int)((back[i].r.size*10)/back[i].r.totalsize); p=minimum(10,p); for(j=0;j<p;j++) printf("*"); for(j=0;j<(10-p);j++) printf("-"); } else { printf(LLintP,back[i].r.size); } printf("]"); //} else if (back[i].status==0) { // strcpy(s,"ENDED"); } printf("\n"); i++; } io_flush; } } // dΘbug graphique #if BDEBUG==2 { char s[12]; int i=0; _GOTOXY(1,1); printf("Rate=%d B/sec\n",(int) (new_stat_bytes/(time_local()-HTS_STAT.stat_timestart))); while(i<minimum(back_max,160)) { if (back[i].status>0) { sprintf(s,"%d",back[i].r.size); } else if (back[i].status==0) { strcpy(s,"ENDED"); } else strcpy(s," - "); while(strlen(s)<8) strcat(s," "); printf("%s",s); io_flush; i++; } } #endif #if BDEBUG==1 printf("statuscode=%d with %s / msg=%s\n",r.statuscode,r.contenttype,r.msg); #endif } /*else { #if BDEBUG==1 printf("back index error\n"); #endif } */ } // FIN --RECUPERATION LIEN--- // ------------------------------------------------------------ } else { // lien vide.. if (opt.errlog) { fprintf(opt.errlog,"Error Link empty"LF); test_flush; error=1; } } // test si url existe (non vide!) // ---tester taille a posteriori--- // tester r.adr if (!error) { // erreur, pas de fichier chargΘ: if ((!r.adr) && (r.is_write==0) && (r.statuscode!=301) && (r.statuscode!=302) && (r.statuscode!=303) && (r.statuscode!=307) && (r.statuscode!=412) && (r.statuscode!=416) ) { error=1; // peut Ωtre que le fichier Θtait trop gros? if ((istoobig(r.totalsize,opt.maxfile_html,opt.maxfile_nonhtml,r.contenttype)) || (istoobig(r.totalsize,opt.maxfile_html,opt.maxfile_nonhtml,r.contenttype))) { error=0; if (opt.errlog) { fspc(opt.errlog,"warning"); fprintf(opt.errlog,"Big file cancelled according to user's preferences: %s%s"LF,urladr,urlfil); test_flush; } } error=1; // ne pas traiter la suite -- euhh si finalement.. } } // ---fin tester taille a posteriori--- // -------------------- // REAL MEDIA HACK // Check if we have to load locally the file // -------------------- if (!error) { if (r.adr==NULL) { // Written file if (may_be_hypertext_mime(r.contenttype)) { // to parse! LLint sz; sz=fsize(savename); if (sz>0) { // ok, exists! if (sz < 512) { // ok, small file --> to parse! FILE* fp=fopen(savename,"rb"); if (fp) { r.adr=malloc((int)sz + 2); if (r.adr) { fread(r.adr,(int)sz,1,fp); r.size=sz; // remove (temporary) file! remove(savename); } fclose(fp); } } } } } } // EN OF REAL MEDIA HACK // ---stockage en cache--- // stocker dans le cache? if (!error) { if (ptr>0) { if (liens[ptr]) { cache_mayadd(&opt,&cache,&r,urladr,urlfil,savename); #if 0 if (opt.cache) { if (cache.dat!=NULL) { // c'est le seul endroit ou l'on ajoute des elements dans le cache (fichier entier ou header) // on stocke tout fichier "ok", mais Θgalement les rΘponses 404,301,302... if ((r.statuscode==200) /* stocker rΘponse standard, plus */ || (r.statuscode==204) /* no content */ || (r.statuscode==301) /* moved perm */ || (r.statuscode==302) /* moved temp */ || (r.statuscode==303) /* moved temp */ || (r.statuscode==307) /* moved temp */ || (r.statuscode==401) /* authorization */ || (r.statuscode==403) /* unauthorized */ || (r.statuscode==404) /* not found */ || (r.statuscode==410) /* gone */ ) { /* ne pas stocker si la page gΘnΘrΘe est une erreur */ if (!r.is_file) { // stocker fichiers (et robots.txt) if ( (strnotempty(savename)) || (strcmp(urlfil,"/robots.txt")==0)) { // ajouter le fichier au cache cache_add(r,urladr,urlfil,savename,cache.ndx,cache.dat,opt.all_in_cache); } } } } } #endif } else error=1; } } // ---fin stockage en cache--- // DEBUT rattrapage des 301,302,307.. // ------------------------------------------------------------ if (!error) { ////////{ // on a chargΘ un fichier en plus // if (!error) stat_loaded+=r.size; // ------------------------------------------------------------ // Rattrapage des 301,302,307 (moved) et 412,416 - les 304 le sont dans le backing // ------------------------------------------------------------ if ( (r.statuscode==301) || (r.statuscode==302) || (r.statuscode==303) || (r.statuscode==307) ) { //if (r.adr!=NULL) { // adr==null si fichier direct. [catch: davename normalement si cgi] //int i=0; char *rn=NULL; char* p; if ( (opt.debug>0) && (opt.errlog!=NULL) ) { //if (opt.errlog) { fspc(opt.errlog,"warning"); fprintf(opt.errlog,"%s for %s%s"LF,r.msg,urladr,urlfil); test_flush; } #if 0 //do { // if (strfield(r.adr+i,"href=")) { // URL trouvΘe #endif { char mov_url[HTS_URLMAXSIZE*2],mov_adr[HTS_URLMAXSIZE*2],mov_fil[HTS_URLMAXSIZE*2]; int n=0; int reponse=0; mov_url[0]='\0'; mov_adr[0]='\0'; mov_fil[0]='\0'; // //printf("location panic! %s\n",r.location); ////p=r.adr+i; ////p+=5; // sauter href p=r.location; while(is_space(*p)) p++; // sauter espaces, " & cie while((!is_space(p[n])) && (p[n] != 0) && (p[n] != '>')) n++; // compter caractΦres strcpy (mov_url,""); strncat(mov_url,p,n); // copier URL // url qque -> adresse+fichier if ((reponse=ident_url_relatif(mov_url,urladr,urlfil,mov_adr,mov_fil))>=0) { int get_it=0; // ne pas prendre le fichier α la mΩme adresse par dΘfaut int set_prio_to=0; // pas de priotitΘ fixΘd par wizard //if (ident_url(mov_url,mov_adr,mov_fil)!=-1) { // ok URL reconnue // c'est (en gros) la mΩme URL.. // si c'est un problΦme de casse dans le host c'est que le serveur est buggΘ // ("RFC says.." : host name IS case insensitive) if ((strfield2(mov_adr,urladr)!=0) && (strfield2(mov_fil,urlfil)!=0)) { // identique α casse prΦs // on tourne en rond if (strcmp(mov_fil,urlfil)==0) { error=1; get_it=-1; // ne rien faire if (opt.errlog) { fspc(opt.errlog,"warning"); fprintf(opt.errlog,"Can not bear crazy server (%s) for %s%s"LF,r.msg,urladr,urlfil); test_flush; } } else { // mauvaise casse, effacer entrΘe dans la pile et rejouer une fois get_it=1; } } else { if (ishtml(mov_url)==0) { // pas mΩme adresse MAIS c'est un fichier (pas de page moved possible) // -> on prend α cette adresse, le lien sera enregistrΘ avec lien_record() (hash) if ((opt.debug>1) && (opt.log!=NULL)) { fspc(opt.log,"debug"); fprintf(opt.log,"wizard link test for moved file at %s%s.."LF,mov_adr,mov_fil); test_flush; } if (hts_acceptlink(&opt,ptr,lien_tot,liens, mov_adr,mov_fil, filters,&filptr,filter_max, &robots, &set_prio_to, NULL) != 1) { /* nouvelle adresse non refusΘe ? */ get_it=1; if ((opt.debug>1) && (opt.log!=NULL)) { fspc(opt.log,"debug"); fprintf(opt.log,"moved link accepted: %s%s"LF,mov_adr,mov_fil); test_flush; } } } /* sinon traitΘ normalement */ } //if ((strfield2(mov_adr,urladr)!=0) && (strfield2(mov_fil,urlfil)!=0)) { // identique α casse prΦs if (get_it==1) { // court-circuiter le reste du traitement // et reculer pour mieux sauter if (opt.errlog) { fspc(opt.errlog,"warning"); fprintf(opt.errlog,"Warning wrong case ignored for %s%s (real one is %s%s)"LF,urladr,urlfil,mov_adr,mov_fil); test_flush; } // canceller lien actuel error=1; strcpy(liens[ptr]->adr,"!"); // caractΦre bidon (invalide hash) #if HTS_HASH #else liens[ptr]->sav_len=-1; // taille invalide #endif // noter NOUVEAU lien { char mov_sav[HTS_URLMAXSIZE*2]; // calculer lien et Θventuellement modifier addresse/fichier if (url_savename(mov_adr,mov_fil,mov_sav,NULL,NULL,liens[liens[ptr]->precedent]->adr,liens[liens[ptr]->precedent]->fil,&opt,liens,lien_tot,back,back_max,&cache,&hash,ptr,numero_passe)!=-1) { if (hash_read(&hash,mov_sav,"",0)<0) { // n'existe pas dΘja // enregistrer lien (MACRO) avec SAV IDENTIQUE liens_record(mov_adr,mov_fil,liens[ptr]->sav,"",""); //liens_record(mov_adr,mov_fil,mov_sav,"",""); if (liens[lien_tot]!=NULL) { // OK, pas d'erreur // mode test? liens[lien_tot]->testmode=liens[ptr]->testmode; liens[lien_tot]->link_import=0; // mode normal if (!set_prio_to) liens[lien_tot]->depth=liens[ptr]->depth; else liens[lien_tot]->depth=max(0,min(set_prio_to-1,liens[ptr]->depth)); // PRIORITE NULLE (catch page) liens[lien_tot]->pass2=max(liens[ptr]->pass2,numero_passe); liens[lien_tot]->retry=liens[ptr]->retry; liens[lien_tot]->premier=liens[ptr]->premier; liens[lien_tot]->precedent=liens[ptr]->precedent; lien_tot++; } else { // oups erreur, plus de mΘmoire!! printf("PANIC! : Not enough memory [%d]\n",__LINE__); if (opt.errlog) { fprintf(opt.errlog,"Not enough memory, can not re-allocate %d bytes"LF,(add_tab_alloc+1)*sizeof(lien_url)); test_flush; } //if (opt.getmode & 1) { if (fp) { fclose(fp); fp=NULL; } } XH_uninit; // dΘsallocation mΘmoire & buffers return 0; } } else { if ( (opt.debug>0) && (opt.errlog!=NULL) ) { fspc(opt.errlog,"warning"); fprintf(opt.errlog,"moving %s to an existing file %s"LF,liens[ptr]->fil,urlfil); test_flush; } } } } //printf("-> %s %s %s\n",liens[lien_tot-1]->adr,liens[lien_tot-1]->fil,liens[lien_tot-1]->sav); // note mΘtaphysique: il se peut qu'il y ait un index.html et un INDEX.HTML // sous DOS ca marche pas trΦs bien... mais comme je suis gΘnial url_savename() // est α mΩme de rΘgler ce problΦme } else if (get_it==0) { // adresse vraiment diffΘrente et potentiellement en html (pas de possibilitΘ de bouger la page tel quel α cause des <img src..> et cie) rn=(char*) calloct(8192,1); if (rn!=NULL) { // On prΘpare une page qui sautera immΘdiatement sur la bonne URL // Le scanner re-changera, ensuite, cette URL, pour la mirrorer! strcpy(rn,"<HTML>"CRLF); strcat(rn,"<!-- Created by HTTrack Website Copier/"HTTRACK_VERSION" "HTTRACK_AFF_AUTHORS" -->"CRLF); strcat(rn,"<HEAD>"CRLF"<TITLE>Page has moved</TITLE>"CRLF"</HEAD>"CRLF"<BODY>"CRLF); strcat(rn,"<META HTTP-EQUIV=\"Refresh\" CONTENT=\"0; URL="); strcat(rn,mov_url); // URL strcat(rn,"\">"CRLF); strcat(rn,"<A HREF=\""); strcat(rn,mov_url); strcat(rn,"\">"); strcat(rn,"<B>Click here...</B></A>"CRLF); strcat(rn,"</BODY>"CRLF); strcat(rn,"<!-- Created by HTTrack Website Copier/"HTTRACK_VERSION" "HTTRACK_AFF_AUTHORS" -->"CRLF); strcat(rn,"</HTML>"CRLF); // changer la page if (r.adr) { freet(r.adr); r.adr=NULL; } r.adr=rn; r.size=strlen(r.adr); strcpy(r.contenttype,"text/html"); if (opt.errlog) { fspc(opt.errlog,"warning"); fprintf(opt.errlog,"File has moved from %s%s to %s"LF,urladr,urlfil,mov_url); test_flush; } // dΘclarer page comme α Θcraser par le fichier si fichier binaire // on va donc modifier la structure physique du site // MAIS, en cas d'update, cela fonctionnera, car: // 1. page moved: pas en cache (moved) // 2. fichier qui Θcrase: mΩme en cas de get avec range:, comme c'est une erreur il // n'y aura pas de rΘponse "partial content" /* if (ishtml(mov_url)==0) { if (!fexist(fconcat(opt.path_log,"moved.lst"))) { FILE* fp=fopen(fconcat(opt.path_log,"moved.lst"),"wb"); if (fp) fclose(fp); } { FILE* fp=fopen(fconcat(opt.path_log,"moved.lst"),"ab"); if (fp) { fprintf(fp,"%s\n",mov_url); fclose(fp); } } } */ } } } else { if (opt.errlog) { fspc(opt.errlog,"error"); if (reponse==-2) fprintf(opt.errlog,"Protocol ftp:// not supported for %s in file %s"LF,urladr,urlfil); else fprintf(opt.errlog,"Unrecoverable %s for %s%s (error move to %s)"LF,r.msg,urladr,urlfil,mov_url); test_flush; } error=1; // URL non reconnue } } #if 0 // i++; //} while((i<r.size) && (rn==NULL) && (error==0)); #endif // erreur HTTP (ex: 404, not found) } else if ( (r.statuscode==412) || (r.statuscode==416) ) { // Precondition Failed, c'est α dire pour nous redemander TOUT le fichier if (fexist(liens[ptr]->sav)) { remove(liens[ptr]->sav); // Eliminer if (!fexist(liens[ptr]->sav)) { // Bien ΘliminΘ? (sinon on boucle..) #if HDEBUG printf("Partial content NOT up-to-date, reget all file for %s\n",liens[ptr]->sav); #endif if ( (opt.debug>1) && (opt.errlog!=NULL) ) { //if (opt.errlog) { fspc(opt.errlog,"debug"); fprintf(opt.errlog,"Partial file reget (%s) for %s%s"LF,r.msg,urladr,urlfil); test_flush; } // enregistrer le MEME lien (MACRO) liens_record(liens[ptr]->adr,liens[ptr]->fil,liens[ptr]->sav,"",""); if (liens[lien_tot]!=NULL) { // OK, pas d'erreur liens[lien_tot]->testmode=liens[ptr]->testmode; // mode test? liens[lien_tot]->link_import=0; // pas mode import liens[lien_tot]->depth=liens[ptr]->depth; liens[lien_tot]->pass2=max(liens[ptr]->pass2,numero_passe); liens[lien_tot]->retry=liens[ptr]->retry; liens[lien_tot]->premier=liens[ptr]->premier; liens[lien_tot]->precedent=ptr; lien_tot++; // // canceller lien actuel error=1; strcpy(liens[ptr]->adr,"!"); // caractΦre bidon (invalide hash) #if HTS_HASH #else liens[ptr]->sav_len=-1; // taille invalide #endif // } else { // oups erreur, plus de mΘmoire!! printf("PANIC! : Not enough memory [%d]\n",__LINE__); if (opt.errlog) { fprintf(opt.errlog,"Not enough memory, can not re-allocate %d bytes"LF,(add_tab_alloc+1)*sizeof(lien_url)); test_flush; } //if (opt.getmode & 1) { if (fp) { fclose(fp); fp=NULL; } } XH_uninit; // dΘsallocation mΘmoire & buffers return 0; } } else { if (opt.errlog!=NULL) { fspc(opt.errlog,"error"); fprintf(opt.errlog,"Can not remove old file %s"LF,urlfil); test_flush; } } } else { if (opt.errlog!=NULL) { fspc(opt.errlog,"warning"); fprintf(opt.errlog,"Unexpected 412/416 error (%s) for %s%s"LF,r.msg,urladr,urlfil); test_flush; } } } else if (r.statuscode!=200) { int can_retry=0; // cas o∙ l'on peut reessayer // -2=timeout -3=rateout (interne α httrack) switch(r.statuscode) { //case -1: can_retry=1; break; case -2: if (opt.hostcontrol) { // timeout et retry ΘpuisΘs if ((opt.hostcontrol & 1) && (liens[ptr]->retry<=0)) { if ((opt.debug>1) && (opt.log!=NULL)) { fspc(opt.log,"debug"); fprintf(opt.log,"Link banned: %s%s"LF,urladr,urlfil); test_flush; } host_ban(&opt,liens,ptr,lien_tot,back,back_max,filters,filter_max,&filptr,jump_identification(urladr)); if ((opt.debug>1) && (opt.log!=NULL)) { fspc(opt.log,"debug"); fprintf(opt.log,"Info: previous log - link banned: %s%s"LF,urladr,urlfil); test_flush; } } else can_retry=1; } else can_retry=1; break; case -3: if ((opt.hostcontrol) && (liens[ptr]->retry<=0)) { // too slow if (opt.hostcontrol & 2) { if ((opt.debug>1) && (opt.log!=NULL)) { fspc(opt.log,"debug"); fprintf(opt.log,"Link banned: %s%s"LF,urladr,urlfil); test_flush; } host_ban(&opt,liens,ptr,lien_tot,back,back_max,filters,filter_max,&filptr,jump_identification(urladr)); if ((opt.debug>1) && (opt.log!=NULL)) { fspc(opt.log,"debug"); fprintf(opt.log,"Info: previous log - link banned: %s%s"LF,urladr,urlfil); test_flush; } } else can_retry=1; } else can_retry=1; break; case -4: // connect closed can_retry=1; break; case -5: // other (non fatal) error can_retry=1; break; case 408: case 409: case 500: case 502: case 504: can_retry=1; break; } if ( strcmp(liens[ptr]->fil,"/primary") ) { // pas primary (page 0) if ((liens[ptr]->retry<=0) || (!can_retry) ) { // retry ΘpuisΘs (ou retry impossible) if (opt.errlog) { if ((opt.retry>0) && (can_retry)){ fspc(opt.errlog,"error"); fprintf(opt.errlog,"\"%s\" (%d) after %d retries at link %s%s (from %s%s)"LF,r.msg,r.statuscode,opt.retry,urladr,urlfil,liens[liens[ptr]->precedent]->adr,liens[liens[ptr]->precedent]->fil); } else { if (r.statuscode==-10) { // test OK if ((opt.debug>0) && (opt.errlog!=NULL)) { fspc(opt.errlog,"info"); fprintf(opt.errlog,"Test OK at link %s%s (from %s%s)"LF,urladr,urlfil,liens[liens[ptr]->precedent]->adr,liens[liens[ptr]->precedent]->fil); } } else { if (strcmp(urlfil,"/robots.txt")) { // ne pas afficher d'infos sur robots.txt par dΘfaut fspc(opt.errlog,"error"); fprintf(opt.errlog,"\"%s\" (%d) at link %s%s (from %s%s)"LF,r.msg,r.statuscode,urladr,urlfil,liens[liens[ptr]->precedent]->adr,liens[liens[ptr]->precedent]->fil); } else { if (opt.debug>0) { // on fera un alert si le retry Θchoue fspc(opt.errlog,"info"); fprintf(opt.errlog,"No robots.txt rules at %s"LF,urladr); test_flush; } } } } test_flush; } // ici on teste si on doit enregistrer la page tout de mΩme if (opt.errpage) { // NO error in trop level // due to the "no connection -> previous restored" hack if (liens[ptr]->precedent != 0) { store_errpage=1; } } } else { // retry!! if (opt.debug>0) { // on fera un alert si le retry Θchoue fspc(opt.errlog,"warning"); fprintf(opt.errlog,"Retry after error %d (%s) at link %s%s (from %s%s)"LF,r.statuscode,r.msg,urladr,urlfil,liens[liens[ptr]->precedent]->adr,liens[liens[ptr]->precedent]->fil); test_flush; } // redemander fichier liens_record(urladr,urlfil,savename,"",""); if (liens[lien_tot]!=NULL) { // OK, pas d'erreur liens[lien_tot]->testmode=liens[ptr]->testmode; // mode test? liens[lien_tot]->link_import=0; // pas mode import liens[lien_tot]->depth=liens[ptr]->depth; liens[lien_tot]->pass2=max(liens[ptr]->pass2,numero_passe); liens[lien_tot]->retry=liens[ptr]->retry-1; // moins 1 retry! liens[lien_tot]->premier=liens[ptr]->premier; liens[lien_tot]->precedent=liens[ptr]->precedent; lien_tot++; } else { // oups erreur, plus de mΘmoire!! printf("PANIC! : Not enough memory [%d]\n",__LINE__); if (opt.errlog) { fspc(opt.errlog,"panic"); fprintf(opt.errlog,"Not enough memory, can not re-allocate %d bytes"LF,(add_tab_alloc+1)*sizeof(lien_url)); test_flush; } //if (opt.getmode & 1) { if (fp) { fclose(fp); fp=NULL; } } XH_uninit; // dΘsallocation mΘmoire & buffers return 0; } } } else { if (opt.errlog) { fspc(opt.errlog,"info"); fprintf(opt.errlog,"Info: no robots.txt at %s%s"LF,urladr,urlfil); } } if (!store_errpage) { if (r.adr) { freet(r.adr); r.adr=NULL; } // dΘsalloc error=1; // erreur! } } // FIN rattrapage des 301,302,307.. // ------------------------------------------------------------ } // if !error } // if !error if (!error) { #if DEBUG_SHOWTYPES if (strstr(REG,r.contenttype)==NULL) { strcat(REG,r.contenttype); strcat(REG,"\n"); printf("%s\n",r.contenttype); io_flush; } #endif // ------------------------------------------------------ // ok, fichier chargΘ localement // ------------------------------------------------------ // VΘrificateur d'intΘgritΘ #if DEBUG_CHECKINT { int i; for(i=0;i<back_max;i++) { char si[256]; sprintf(si,"Test global aprΦs back_wait, index %d",i); _CHECKINT(&back[i],si) } } #endif /* info: updated */ if (ptr>0) { // "mis α jour" if ((!r.notmodified) && (opt.is_update) && (!store_errpage)) { // page modifiΘe if (strnotempty(savename)) { HTS_STAT.stat_updated_files++; if (opt.log!=NULL) { //if ((opt.debug>0) && (opt.log!=NULL)) { fspc(opt.log,"info"); fprintf(opt.log,"File updated: %s%s"LF,urladr,urlfil); test_flush; } } } else { if (!store_errpage) { if ( (opt.debug>0) && (opt.log!=NULL) ) { fspc(opt.log,"info"); fprintf(opt.log,"File recorded: %s%s"LF,urladr,urlfil); test_flush; } } } } // ------------------------------------------------------ // traitement (parsing) // ------------------------------------------------------ // traiter if ( ( (is_hypertext_mime(r.contenttype)) /* Is HTML or Js, .. */ || (may_be_hypertext_mime(r.contenttype) && (r.adr) ) /* Is real media, .. */ ) && (liens[ptr]->depth>0) /* Depth > 0 (recurse depth) */ && (r.adr!=NULL) /* HTML Data exists */ && (r.size>0) /* And not empty */ && (!store_errpage) /* Not an html error page */ && (savename[0]!='\0') /* Output filename exists */ ) { // ne traiter que le html si autorisΘ // -- -- -- -- // Parsing HTML if (!error) { // I'll have to segment this part #include "htsparse.c" } // Fin parsing HTML // -- -- -- -- } // si text/html // -- -- -- else { // sauver fichier quelconque // -- -- -- // sauver fichier /* En cas d'erreur, vΘrifier que fichier d'erreur existe */ if (strnotempty(savename) == 0) { // chemin de sauvegarde existant if (strcmp(urlfil,"/robots.txt")==0) { // pas robots.txt if (store_errpage) { // c'est une page d'erreur int create_html_warning=0; int create_gif_warning=0; switch (ishtml(urlfil)) { /* pas fichier html */ case 0: /* non html */ { char buff[256]; guess_httptype(buff,urlfil); if (strcmp(buff,"image/gif")==0) create_gif_warning=1; } break; case 1: /* html */ if (!r.adr) { } break; default: /* don't know.. */ break; } /* CrΘer message d'erreur ? */ if (create_html_warning) { char* adr=(char*)malloc(strlen(HTS_DATA_ERROR_HTML)+1100); if ( (opt.debug>0) && (opt.log!=NULL) ) { fspc(opt.log,"info"); fprintf(opt.log,"Creating HTML warning file (%s)"LF,r.msg); test_flush; } if (adr) { if (r.adr) { freet(r.adr); r.adr=NULL; } sprintf(adr,HTS_DATA_ERROR_HTML,r.msg); r.adr=adr; } } else if (create_gif_warning) { char* adr=(char*)malloc(HTS_DATA_UNKNOWN_GIF_LEN); if ( (opt.debug>0) && (opt.log!=NULL) ) { fspc(opt.log,"info"); fprintf(opt.log,"Creating GIF dummy file (%s)"LF,r.msg); test_flush; } if (r.adr) { freet(r.adr); r.adr=NULL; } bcopy(HTS_DATA_UNKNOWN_GIF,adr,HTS_DATA_UNKNOWN_GIF_LEN); r.adr=adr; } } } } if (strnotempty(savename) == 0) { // pas de chemin de sauvegarde if (strcmp(urlfil,"/robots.txt")==0) { // robots.txt if (r.adr) { int bptr=0; char line[256]; char buff[8192]; char infobuff[8192]; int record=0; line[0]='\0'; buff[0]='\0'; infobuff[0]='\0'; // #if DEBUG_ROBOTS printf("robots.txt dump:\n%s\n",r.adr); #endif do { bptr+=binput(r.adr+bptr,line,200); if (strfield(line,"user-agent:")) { char* a; a=line+11; while(*a==' ') a++; // sauter espace(s) if (*a == '*') { if (record != 2) record=1; // c pour nous } else if (strfield(a,"httrack")) { buff[0]='\0'; // re-enregistrer infobuff[0]='\0'; record=2; // locked #if DEBUG_ROBOTS printf("explicit disallow for httrack\n"); #endif } else record=0; } else if (record) { if (strfield(line,"disallow:")) { char* a; a=strchr(line,'#'); if (a) *a='\0'; while((line[strlen(line)-1]==' ') || (line[strlen(line)-1]==10) || (line[strlen(line)-1]==13)) line[strlen(line)-1]='\0'; // supprimer espaces a=line+9; while((*a==' ') || (*a==10) || (*a==13)) a++; // sauter espace(s) if (strnotempty(a)) { if (strcmp(a,"/")) { /* ignoring disallow: / */ strcat(buff,a); strcat(buff,"\n"); if (strnotempty(infobuff)) strcat(infobuff,", "); strcat(infobuff,a); } else { if (opt.errlog!=NULL) { fspc(opt.errlog,"info"); fprintf(opt.errlog,"Note: %s robots.txt rules are too restrictive, ignoring /"LF,urladr); test_flush; } } } } } } while( (bptr<r.size) && (strlen(buff)<4096) ); if (strnotempty(buff)) { checkrobots_set(&robots,urladr,buff); if (opt.log!=NULL) { if (opt.log != opt.errlog) { fspc(opt.log,"info"); fprintf(opt.log,"Note: robots.txt forbidden links for %s are: %s"LF,urladr,infobuff); test_flush; } } if (opt.errlog!=NULL) { fspc(opt.errlog,"info"); fprintf(opt.errlog,"Note: due to %s remote robots.txt rules, links begining with these path will be forbidden: %s (see in the options to disable this)"LF,urladr,infobuff); test_flush; } } } } } else if (r.is_write) { // dΘja sauvΘ sur disque if (!ishttperror(r.statuscode)) HTS_STAT.stat_files++; HTS_STAT.stat_bytes+=r.size; //printf("ok......\n"); } else { // Si on doit sauver une page HTML sans la scanner, cela signifie que le niveau de // rΘcursion nous en empΩche // Dans ce cas on met un fichier indiquant ce fait // Si par la suite on doit retraiter ce fichier avec un niveau de rΘcursion plus // fort, on supprimera le readme, et on scannera le fichier html! // note: sautΘ si store_errpage (cαd si page d'erreur, non α scanner!) if ( (is_hypertext_mime(r.contenttype)) && (!store_errpage) && (r.size>0)) { // c'est du html!! char tempo[HTS_URLMAXSIZE*2]; FILE* fp; tempo[0]='\0'; strcpy(tempo,savename); strcat(tempo,".readme"); #if HTS_DOSNAME // remplacer / par des slash arriΦre { int i=0; while(tempo[i]) { if (tempo[i]=='/') tempo[i]='\\'; i++; } } // a partir d'ici le slash devient antislash #endif if ((fp=fopen(tempo,"wb"))!=NULL) { fprintf(fp,"Info-file generated by HTTrack Website Copier "HTTRACK_VERSION""CRLF""CRLF); fprintf(fp,"The file %s has not been scanned by HTS"CRLF,savename); fprintf(fp,"Some links contained in it may be unreachable locally."CRLF); fprintf(fp,"If you want to get these files, you have to set an upper recurse level, "); fprintf(fp,"and to rescan the URL."CRLF); fclose(fp); #if HTS_WIN==0 chmod(tempo,HTS_ACCESS_FILE); #endif usercommand(0,NULL,antislash(tempo)); } if ( (opt.debug>0) && (opt.errlog!=NULL) ) { fspc(opt.errlog,"warning"); fprintf(opt.errlog,"Warning: store %s without scan: %s"LF,r.contenttype,savename); test_flush; } } else { if ((opt.getmode & 2)!=0) { // ok autorisΘ if ( (opt.debug>1) && (opt.log!=NULL) ) { fspc(opt.log,"debug"); fprintf(opt.log,"Store %s: %s"LF,r.contenttype,savename); test_flush; } } else { // lien non autorisΘ! (ex: cgi-bin en html) if ((opt.debug>1) && (opt.log!=NULL)) { fspc(opt.log,"debug"); fprintf(opt.log,"non-html file ignored after upload at %s : %s"LF,urladr,urlfil); test_flush; } freet(r.adr); r.adr=NULL; } } //printf("extern=%s\n",r.contenttype); // ATTENTION C'EST ICI QU'ON SAUVE LE FICHIER!! if (r.adr) { if (filesave(r.adr,(int)r.size,savename)!=0) { if (opt.errlog) { fprintf(opt.errlog,"Unable to save file %s"LF,savename); test_flush; } } else { if (!ishttperror(r.statuscode)) HTS_STAT.stat_files++; HTS_STAT.stat_bytes+=r.size; } } } /* Parsing of other media types (java, ram..) */ /* if (strfield2(r.contenttype,"audio/x-pn-realaudio")) { if ((opt.debug>1) && (opt.log!=NULL)) { fspc(opt.log,"debug"); fprintf(opt.log,"(Real Media): parsing %s"LF,savename); test_flush; } if (fexist(savename)) { // ok, existe bien! FILE* fp=fopen(savename,"r+b"); if (fp) { if (!fseek(fp,0,SEEK_SET)) { char line[HTS_URLMAXSIZE*2]; linput(fp,line,HTS_URLMAXSIZE); if (strnotempty(line)) { if ((opt.debug>1) && (opt.log!=NULL)) { fspc(opt.log,"debug"); fprintf(opt.log,"(Real Media): detected %s"LF,line); test_flush; } } } fclose(fp); } } } else */ if (opt.parsejava) { if (strlen(savename)>6) { // fichier.class if (strfield(savename+strlen(savename)-6,".class")) { // ok c'est une classe if (fexist(savename)) { // ok, existe bien! char err_msg[1100]; int r; err_msg[0]='\0'; //##char* buffer; // JavaParsing f34R! if ((opt.debug>1) && (opt.log!=NULL)) { fspc(opt.log,"debug"); fprintf(opt.log,"(JavaClass catch file): parsing %s"LF,savename); test_flush; } //##buffer=(char*) malloct(32768); //##if (buffer) { // //##strcpy(buffer,"$BUFFER$"); //##hts_add_file(buffer); // dΘclarer buffer while(hts_add_file(NULL,-1) >= 0); // clear chain r=hts_parse_java(savename,(char*) &err_msg); // parsing if (!r) { // error if (opt.errlog) { fprintf(opt.errlog,"Unable to parse java file %s : %s"LF,savename,err_msg); test_flush; } } else { // ok char adr[HTS_URLMAXSIZE*2],fil[HTS_URLMAXSIZE*2],save[HTS_URLMAXSIZE*2]; // nom du fichier α sauver dans la boucle char codebase[HTS_URLMAXSIZE*2]; // codebase classe java char lien[HTS_URLMAXSIZE*2]; //##char* a; int file_position; int pass_fix,prio_fix; codebase[0]='\0'; // if ((opt.debug>1) && (opt.log!=NULL)) { fspc(opt.log,"debug"); fprintf(opt.log,"(JavaClass catch file): parsing finished, now copying links.."LF); test_flush; } // recopie de "creer le lien" // // adr = c'est la mΩme // fil et save: save2 et fil2 prio_fix=maximum(liens[ptr]->depth-1,0); pass_fix=max(liens[ptr]->pass2,numero_passe); if (liens[ptr]->cod) strcpy(codebase,liens[ptr]->cod); // codebase valable pour tt les classes descendantes if (strnotempty(codebase)==0) { // pas de codebase, construire char* a; strcpy(codebase,liens[ptr]->fil); a=codebase+strlen(codebase)-1; while((*a) && (*a!='/') && ((int) a > (int) codebase)) a--; if (*a=='/') *(a+1)='\0'; // couper } else { // couper http:// Θventuel if (strfield(codebase,"http://")) { char tempo[HTS_URLMAXSIZE*2]; char* a=codebase+7; a=strchr(a,'/'); // aprΦs host if (a) { // ** msg erreur et vΘrifier? strcpy(tempo,a); strcpy(codebase,tempo); // couper host } else { if (opt.errlog) { fprintf(opt.errlog,"Unexpected strstr error in base %s"LF,codebase); test_flush; } } } } //##a=buffer; //##strcat(buffer,"&"); // fin du buffer if (!((int) strlen(codebase)<HTS_URLMAXSIZE)) { // trop long if (opt.errlog) { fprintf(opt.errlog,"Codebase too long, parsing skipped (%s)"LF,codebase); test_flush; } //##a=NULL; while(hts_add_file(NULL,-1) >= 0); // clear chain } while ( (file_position=hts_add_file(lien,-1)) >= 0 ) { int dejafait=0; /* //## char* b; // prochain fichier α noter! lien[0]='\0'; b=strchr(a,'&'); // marqueur de fin de chaine (voir hts_add_file) if (b) { if ( ( ((int) b-(int) a) + strlen(codebase)) < HTS_URLMAXSIZE) strncat(lien,a,(int) b-(int) a); // nom du fichier else { if (opt.errlog) { fprintf(opt.errlog,"Error: Java-Parser generated link that exceeds %d bytes"LF,HTS_URLMAXSIZE); test_flush; } } } else a=NULL; if (strnotempty(lien)==0) a=NULL; // fin if (a) a=b+1; */ if (strnotempty(lien)) { // calculer les chemins et noms de sauvegarde if (ident_url_relatif(lien,urladr,codebase,adr,fil)>=0) { // reformage selon chemin int r; // patcher opt pour garder structure originale!! (on ne patche pas les noms dans la classe java!) //##if (!strstr(lien,"://")) { // PAS tester les http://.. inutile (on ne va pas patcher le binaire :-( ) if (1) { char tempo[HTS_URLMAXSIZE*2]; int a,b; tempo[0]='\0'; a=opt.savename_type; b=opt.savename_83; opt.savename_type=0; opt.savename_83=0; // note: adr,fil peuvent Ωtre patchΘs r=url_savename(adr,fil,save,NULL,NULL,NULL,NULL,&opt,liens,lien_tot,back,back_max,&cache,&hash,ptr,numero_passe); opt.savename_type=a; opt.savename_83=b; if (r != -1) { if (savename) { if (lienrelatif(tempo,save,savename)==0) { if ((opt.debug>1) && (opt.log!=NULL)) { fspc(opt.log,"debug"); fprintf(opt.log,"(JavaClass catch file): relative link at %s build with %s and %s: %s"LF,adr,save,savename,tempo); test_flush; } // // xxc xxc xxc xxc TODO java: // rebuild the java class with patched strings... // if (strlen(tempo)<=strlen(lien)) { FILE* fp=fopen(savename,"r+b"); if (fp) { if (!fseek(fp,file_position,SEEK_SET)) { //unsigned short int string_length=strlen(tempo); //fwrite(&valint,sizeof(string_length),1,fp); // xxc xxc ARGH! SI la taille est <, dΘcaler le code ?! } else { if (opt.log!=NULL) { fspc(opt.log,"debug"); fprintf(opt.log,"(JavaClass catch file): unable to patch: %s"LF,savename); test_flush; } } fclose(fp); } else { if (opt.log!=NULL) { fspc(opt.log,"debug"); fprintf(opt.log,"(JavaClass catch file): unable to open: %s"LF,savename); test_flush; } } } else { if (opt.log!=NULL) { fspc(opt.log,"debug"); fprintf(opt.log,"(JavaClass catch file): link too long, unable to write it: %s"LF,tempo); test_flush; } } } } } } else { if ((opt.debug>1) && (opt.log!=NULL)) { fspc(opt.log,"debug"); fprintf(opt.log,"(JavaClass catch file): file not caught: %s"LF,lien); test_flush; } r=-1; } // if (r != -1) { if ((opt.debug>1) && (opt.log!=NULL)) { fspc(opt.log,"debug"); fprintf(opt.log,"(JavaClass catch file): %s%s -> %s (base %s)"LF,adr,fil,save,codebase); test_flush; } // modifiΘ par rapport α l'autre version (cf prio_fix notamment et save2) // vΘrifier que le lien n'a pas dΘja ΘtΘ notΘ // si c'est le cas, alors il faut s'assurer que la prioritΘ associΘe // au fichier est la plus grande des deux prioritΘs // // On part de la fin et on essaye de se presser (Θconomise temps machine) #if HTS_HASH { int i=hash_read(&hash,save,"",0); // lecture type 0 (sav) if (i>=0) { liens[i]->depth=maximum(liens[i]->depth,prio_fix); dejafait=1; } } #else { register int l; register int i; l=strlen(save); for(i=lien_tot-1;(i>=0) && (dejafait==0);i--) { if (liens[i]->sav_len==l) { // mΩme taille de chaεne if (strcmp(liens[i]->sav,save)==0) { // existe dΘja liens[i]->depth=maximum(liens[i]->depth,prio_fix); dejafait=1; } } } } #endif if (!dejafait) { // // >>>> CREER LE LIEN JAVA <<<< // enregistrer fichier de java (MACRO) liens_record(adr,fil,save,"",""); if (liens[lien_tot]==NULL) { // erreur, pas de place rΘservΘe printf("PANIC! : Not enough memory [%d]\n",__LINE__); if (opt.errlog) { fprintf(opt.errlog,"Not enough memory, can not re-allocate %d bytes"LF,(add_tab_alloc+1)*sizeof(lien_url)); test_flush; } // if ((opt.getmode & 1) && (ptr>0)) { if (fp) { fclose(fp); fp=NULL; } } XH_extuninit; // dΘsallocation mΘmoire & buffers return 0; } // mode test? liens[lien_tot]->testmode=0; // pas mode test liens[lien_tot]->link_import=0; // pas mode import // Θcrire autres paramΦtres de la structure-lien //if (meme_adresse) liens[lien_tot]->premier=liens[ptr]->premier; //else // sinon l'objet pΦre est le prΘcΘdent lui mΩme // liens[lien_tot]->premier=ptr; liens[lien_tot]->precedent=ptr; // noter la prioritΘ liens[lien_tot]->depth=prio_fix; liens[lien_tot]->pass2=max(pass_fix,numero_passe); liens[lien_tot]->retry=opt.retry; //strcpy(liens[lien_tot]->adr,adr); //strcpy(liens[lien_tot]->fil,fil); //strcpy(liens[lien_tot]->sav,save); if ((opt.debug>1) && (opt.log!=NULL)) { fspc(opt.log,"debug"); fprintf(opt.log,"(JavaClass catch file): OK, NOTE: %s%s -> %s"LF,liens[lien_tot]->adr,liens[lien_tot]->fil,liens[lien_tot]->sav); test_flush; } lien_tot++; // UN LIEN DE PLUS } } } } } } //##// effacer buffer temporaire //##if (buffer) freet(buffer); buffer=NULL; //##} // if buffer } // if exist } // if .class } // if strlen-savename } // if opt.parsejava } // text/html ou autre } // if !error jump_if_done: // libΘrer les liens if (r.adr) { freet(r.adr); r.adr=NULL; } // libΘrer la mΘmoire! // prochain lien ptr++; // faut-il sauter le(s) lien(s) suivant(s)? (fichiers images α passer aprΦs les html) if (opt.getmode & 4) { // sauver les non html aprΦs // sauter les fichiers selon la passe if (!numero_passe) { while((ptr<lien_tot)?( liens[ptr]->pass2):0) ptr++; } else { while((ptr<lien_tot)?( ! liens[ptr]->pass2):0) ptr++; } if (ptr>=lien_tot) { // fin de boucle if (!numero_passe) { // premiΦre boucle if ((opt.debug>1) && (opt.log!=NULL)) { fprintf(opt.log,LF"Now getting non-html files..."LF); test_flush; } numero_passe=1; // seconde boucle ptr=0; // prochain pass2 while((ptr<lien_tot)?(!liens[ptr]->pass2):0) ptr++; //printf("first link==%d\n"); } } } // a-t-on dΘpassΘ le quota? if ((opt.maxsite>0) && (HTS_STAT.stat_bytes>=opt.maxsite)) { if (opt.errlog) { fprintf(opt.errlog,"More than %d bytes have been transfered.. giving up"LF,opt.maxsite); test_flush; } ptr=lien_tot; } else if ((opt.maxtime>0) && ((time_local()-HTS_STAT.stat_timestart)>opt.maxtime)) { if (opt.errlog) { fprintf(opt.errlog,"More than %d seconds passed.. giving up"LF,opt.maxtime); test_flush; } ptr=lien_tot; } else if (exit_xh) { // sortir if (opt.errlog) { fspc(opt.errlog,"info"); fprintf(opt.errlog,"Exit requested by shell or user"LF); test_flush; } ptr=lien_tot; } } while(ptr<lien_tot); // // // // no data transfered, no data saved // we assume that something was bad (no connection) // just backup old cache and restore everything if ( (HTS_STAT.stat_files == 0) && (new_stat_bytes < 2048) ) { if (opt.errlog) { fspc(opt.errlog,"info"); fprintf(opt.errlog,"No data seems to have been transfered during this session! : restoring previous one!"LF); test_flush; } XH_uninit; if ( (fexist(fconcat(opt.path_log,"hts-cache/old.dat"))) && (fexist(fconcat(opt.path_log,"hts-cache/old.ndx"))) ) { remove(fconcat(opt.path_log,"hts-cache/new.dat")); remove(fconcat(opt.path_log,"hts-cache/new.ndx")); remove(fconcat(opt.path_log,"hts-cache/new.lst")); rename(fconcat(opt.path_log,"hts-cache/old.dat"),fconcat(opt.path_log,"hts-cache/new.dat")); rename(fconcat(opt.path_log,"hts-cache/old.ndx"),fconcat(opt.path_log,"hts-cache/new.ndx")); rename(fconcat(opt.path_log,"hts-cache/old.lst"),fconcat(opt.path_log,"hts-cache/new.lst")); } exit_xh=2; /* interrupted (no connection detected) */ return 1; } // purger! if (opt.delete_old) { if (cache.lst) { FILE *old_lst,*new_lst; // #if HTS_ANALYSTE==2 _hts_in_html_parsing=3; #endif // fclose(cache.lst); cache.lst=NULL; old_lst=fopen(fconcat(opt.path_log,"hts-cache/old.lst"),"rb"); if (old_lst) { LLint sz=fsize(fconcat(opt.path_log,"hts-cache/new.lst")); new_lst=fopen(fconcat(opt.path_log,"hts-cache/new.lst"),"rb"); if ((new_lst) && (sz>0)) { char* adr=(char*) malloct((INTsys)sz); if (adr) { if ((int) fread(adr,1,(INTsys)sz,new_lst) == sz) { char line[1100]; int purge=0; while(!feof(old_lst)) { linput(old_lst,line,1000); if (!strstr(adr,line)) { // fichier non trouvΘ dans le nouveau? char file[HTS_URLMAXSIZE*2]; strcpy(file,opt.path_html); strcat(file,line+1); file[strlen(file)-1]='\0'; if (fexist(file)) { // toujours sur disque: virer if (opt.log) { fspc(opt.log,"info"); fprintf(opt.log,"Purging %s"LF,file); } remove(file); purge=1; } } } { fseek(old_lst,0,SEEK_SET); while(!feof(old_lst)) { linput(old_lst,line,1000); while(strnotempty(line) && (line[strlen(line)-1]!='/') && (line[strlen(line)-1]!='\\')) { line[strlen(line)-1]='\0'; } if (strnotempty(line)) line[strlen(line)-1]='\0'; if (strnotempty(line)) if (!strstr(adr,line)) { // non trouvΘ? char file[HTS_URLMAXSIZE*2]; strcpy(file,opt.path_html); strcat(file,line+1); while ((strnotempty(file)) && (rmdir(file)==0)) { // ok, ΘliminΘ (existait) purge=1; if (opt.log) { fspc(opt.log,"info"); fprintf(opt.log,"Purging directory %s/"LF,file); while(strnotempty(file) && (file[strlen(file)-1]!='/') && (file[strlen(file)-1]!='\\')) { file[strlen(file)-1]='\0'; } if (strnotempty(file)) file[strlen(file)-1]='\0'; } } } } } // if (!purge) { if (opt.log) { fprintf(opt.log,"No files purged"LF); } } } freet(adr); } fclose(new_lst); } fclose(old_lst); } // #if HTS_ANALYSTE==2 _hts_in_html_parsing=0; #endif } } // fin purge! // Indexation if (opt.kindex) index_finish(opt.path_html); // afficher rΘsumΘ dans log if (opt.log!=NULL) { int error = fspc(NULL,"error"); int warning = fspc(NULL,"warning"); int info = fspc(NULL,"info"); char htstime[256]; // int n=(int) (stat_loaded/(time_local()-HTS_STAT.stat_timestart)); int n=(int) (new_stat_bytes/(time_local()-HTS_STAT.stat_timestart)); sec2str(htstime,time_local()-HTS_STAT.stat_timestart); //fprintf(opt.log,LF"HTS-mirror complete in %s : %d links scanned, %d files written (%d bytes overall) [%d bytes received at %d bytes/sec]"LF,htstime,lien_tot-1,HTS_STAT.stat_files,stat_bytes,stat_loaded,n); fprintf(opt.log,LF"HTTrack mirror complete in %s : %d links scanned, %d files written (%d bytes overall) [%d bytes received at %d bytes/sec]"LF,htstime,(int)lien_tot-1,(int)HTS_STAT.stat_files,(int)HTS_STAT.stat_bytes,(int)new_stat_bytes,(int)n); if (error) fprintf(opt.log,"(%d errors, %d warnings, %d messages)"LF,error,warning,info); else fprintf(opt.log,"(No errors, %d warnings, %d messages)"LF,warning,info); test_flush; } #if DEBUG_HASH // noter les collisions { int i; int empty1=0,empty2=0,empty3=0; for(i=0;i<HTS_HASH_SIZE;i++) { if (hash.hash[0][i] == -1) empty1++; if (hash.hash[1][i] == -1) empty2++; if (hash.hash[2][i] == -1) empty3++; } printf("\n"); printf("Debug info: Hash-table report\n"); printf("Number of files entered: %d\n",hashnumber); printf("Table size: %d\n",HTS_HASH_SIZE); printf("\n"); printf("Longest chain sav: %d, empty: %d\n",longest_hash[0],empty1); printf("Longest chain adr,fil: %d, empty: %d\n",longest_hash[1],empty2); printf("Longest chain former_adr/fil: %d, empty: %d\n",longest_hash[2],empty3); printf("\n"); } #endif // fin afficher rΘsumΘ dans log // dΘsallocation mΘmoire & buffers XH_uninit return 1; // OK } // version 2 pour le reste // flusher si on doit lire peu α peu le fichier #undef test_flush #define test_flush if (opt->flush) { fflush(opt->log); fflush(opt->errlog); } // Estimate transfer rate int engine_stats() { if ( ((mtime_local() - HTS_STAT.imstat_timestart) >= 2000) && (new_stat_bytes>2048) ) { double cdif; double dif; cdif=mtime_local(); dif=cdif - HTS_STAT.imstat_timestart; if (dif) { LLint byt=(int) (new_stat_bytes-HTS_STAT.istat_bytes); HTS_STAT.rate=(LLint)((double) ((double)byt/(dif/1000.0))); // HTS_STAT.istat_bytes=new_stat_bytes; HTS_STAT.imstat_timestart=cdif; } return 1; /* refreshed */ } return 0; } // bannir host (trop lent etc) void host_ban(httrackp* opt,lien_url** liens,int ptr,int lien_tot,lien_back* back,int back_max,char** filters,int filter_max,int* filptr,char* host) { //register int l; register int i; if (host[0]=='!') return; // erreur.. dΘja cancellΘ.. bizzard.. devrait pas arriver // interdire host if (*filptr < filter_max) { strcpy(filters[*filptr],"-"); strcat(filters[*filptr],host); strcat(filters[*filptr],"/*"); // host/ * interdit (*filptr)++; *filptr=minimum(*filptr,filter_max); } // oups if (strlen(host)<=1) { // euhh?? longueur <= 1 if (strcmp(host,"file://")) { //## if (host[0]!=lOCAL_CHAR) { // pas local if (opt->log!=NULL) { fprintf(opt->log,"PANIC! HostCancel detected memory leaks [char %d]"LF,host[0]); test_flush; } return; // purΘe } } // couper connexion for(i=0;i<back_max;i++) { if (back[i].status>=0) // rΘception OU prΩt if (strfield2(back[i].url_adr,host)) { #if HTS_DEBUG_CLOSESOCK DEBUG_W("host control: deletehttp\n"); #endif back[i].status=0; // terminΘ if (back[i].r.soc!=INVALID_SOCKET) deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET; back[i].r.statuscode=-2; // timeout (peu importe si c'est un traffic jam) strcpy(back[i].r.msg,"Link Cancelled by host control"); if ((opt->debug>1) && (opt->log!=NULL)) { fprintf(opt->log,"Shutdown: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush; } } } // effacer liens //l=strlen(host); for(i=0;i<lien_tot;i++) { //if (liens[i]->adr_len==l) { // mΩme taille de chaεne // Calcul de taille sΘcurisΘe if (liens[i]) { if (liens[i]->adr) { int l = 0; while((liens[i]->adr[l]) && (l<1020)) l++; if ((l > 0) && (l<1020)) { // sΘcuritΘ if (strfield2(jump_identification(liens[i]->adr),host)) { // host if ((opt->debug>1) && (opt->log!=NULL)) { fprintf(opt->log,"Cancel: %s%s"LF,liens[i]->adr,liens[i]->fil); test_flush; } strcpy(liens[i]->adr,"!"); // cancel (invalide hash) #if HTS_HASH #else liens[i]->sav_len=-1; // taille invalide #endif // on efface pas le hash, because si on rencontre le lien, reverif sav.. } } else { if (opt->log!=NULL) { char dmp[1040]; dmp[0]='\0'; strncat(dmp,liens[i]->adr,1024); fprintf(opt->log,"WARNING! HostCancel detected memory leaks [len %d at %d]"LF,l,i); test_flush; fprintf(opt->log,"dump 1024 bytes (address %d): "LF"%s"LF,(int)liens[i]->adr,dmp); test_flush; } } } else { if (opt->log!=NULL) { fprintf(opt->log,"WARNING! HostCancel detected memory leaks [adr at %d]"LF,i); test_flush; } } } else { if (opt->log!=NULL) { fprintf(opt->log,"WARNING! HostCancel detected memory leaks [null at %d]"LF,i); test_flush; } } //} } } // vΘrifier prΘsence de l'arbo int structcheck(char* s) { // vΘrifier la prΘsence des dossier(s) char *a=s; char nom[HTS_URLMAXSIZE*2]; char *b; if (strnotempty(s)==0) return 0; if (strlen(s)>HTS_URLMAXSIZE) return 0; if (structcheck_buff==NULL) { structcheck_buff=(char*) malloct(65536); // ** ** non dΘsallouΘ strcpy(structcheck_buff,"#"); } else if (strlen(structcheck_buff)>65000) { strcpy(structcheck_buff,"#"); // rΘinit.. c'est idiot ** ** } if (structcheck_buff) { b=nom; do { if (*a) *b++=*a++; while((*a!='/') && (*a!='\0')) *b++=*a++; *b='\0'; // pas de ++ pour boucler if (*a=='/') { // toujours dossier if (strnotempty(nom)) { char tempo[HTS_URLMAXSIZE*2]; strcpy(tempo,"#"); strcat(tempo,nom); strcat(tempo,"#"); if (strstr(structcheck_buff,tempo)==NULL) { // non encore crΘΘ strcat(structcheck_buff,"#"); strcat(structcheck_buff,nom); strcat(structcheck_buff,"#"); // ajouter α la liste #if HTS_WIN if (mkdir(fconv(nom))!=0) #else if (mkdir(fconv(nom),HTS_ACCESS_FOLDER)!=0) #endif { #if HTS_REMOVE_ANNOYING_INDEX // might be a filename with same name than this folder // then, remove it to allow folder creation // it happends when servers gives a folder index while // requesting / page // -> if the file can be opened (not a folder) then rename it FILE* fp=fopen(fconv(nom),"ab"); if (fp) { fclose(fp); rename(fconv(nom),fconcat(fconv(nom),".txt")); } // if it fails, that's too bad #if HTS_WIN mkdir(fconv(nom)); #else mkdir(fconv(nom),HTS_ACCESS_FOLDER); #endif #endif // Si existe dΘja renvoie une erreur.. tant pis } #if HTS_WIN==0 chmod(fconv(nom),HTS_ACCESS_FOLDER); #endif } } *b++=*a++; // slash } } while(*a); } return 0; } // sauver un fichier int filesave(char* adr,int len,char* s) { FILE* fp; // Θcrire le fichier if ((fp=filecreate(s))!=NULL) { int nl=0; if (len>0) { nl=(int) fwrite(adr,1,len,fp); } fclose(fp); usercommand(0,NULL,antislash(s)); if (nl!=len) // erreur return -1; } else return -1; return 0; } // ouvrir un fichier (avec chemin Un*x) FILE* filecreate(char* s) { char fname[HTS_URLMAXSIZE*2]; FILE* fp; fname[0]='\0'; // noter lst filenote(s,NULL); // if (*s=='/') strcpy(fname,s+1); else strcpy(fname,s); // pas de / (root!!) // ** SIIIIIII!!! α cause de -O <path> strcpy(fname,s); #if HTS_DOSNAME // remplacer / par des slash arriΦre { int i=0; while(fname[i]) { if (fname[i]=='/') fname[i]='\\'; i++; } } // a partir d'ici le slash devient antislash #endif // construite le chemin si besoin est if (structcheck(s)!=0) { return NULL; } // ouvrir fp=fopen(fname,"wb"); #if HTS_WIN==0 if (fp!=NULL) chmod(fname,HTS_ACCESS_FILE); #endif return fp; } // noter fichier int filenote(char* s,filecreate_params* params) { //int filenote(char* s,char* params) { static FILE* lst = NULL; static char path[HTS_URLMAXSIZE*2]=""; // gestion du fichier liste liste if (params) { //filecreate_params* p = (filecreate_params*) params; strcpy(path,params->path); lst=params->lst; return 0; } else if (lst) { char savelst[HTS_URLMAXSIZE*2]; strcpy(savelst,fslash(s)); // couper chemin? if (strnotempty(path)) { if (strncmp(fslash(path),savelst,strlen(path))==0) { // couper strcpy(savelst,s+strlen(path)); } } fprintf(lst,"[%s]"LF,savelst); fflush(lst); } return 1; } // executer commande utilisateur HTS_INLINE void usercommand(int _exe,char* _cmd,char* file) { static int exe=0; static char cmd[2048]=""; if (_exe) { strcpy(cmd,_cmd); if (strnotempty(cmd)) exe=_exe; else exe=0; } if (exe) { if (strnotempty(file)) { if (strnotempty(cmd)) { usercommand_exe(cmd,file); } } } } void usercommand_exe(char* cmd,char* file) { char temp[8192]; char c[2]=""; int i; temp[0]='\0'; // for(i=0;i<(int) strlen(cmd);i++) { if ((cmd[i]=='$') && (cmd[i+1]=='0')) { strcat(temp,file); i++; } else { c[0]=cmd[i]; c[1]='\0'; strcat(temp,c); } } system(temp); } // Θcrire n espaces dans fp HTS_INLINE int fspc(FILE* fp,char* type) { static int error=0,warning=0,info=0; // if (fp) { char s[256]; time_t tt; struct tm* A; tt=time(NULL); A=localtime(&tt); strftime(s,250,"%H:%M:%S",A); if (strnotempty(type)) fprintf(fp,"%s\t%c%s: \t",s,hichar(*type),type+1); else fprintf(fp,"%s\t \t",s); if (strcmp(type,"warning")==0) warning++; else if (strcmp(type,"error")==0) error++; else if (strcmp(type,"info")==0) info++; } else if (strcmp(type,"warning")==0) return warning; else if (strcmp(type,"error")==0) return error; else if (strcmp(type,"info")==0) return info; return 0; } // vΘrifier taux de transfert void check_rate(double stat_timestart,int maxrate) { // vΘrifier taux de transfert (pas trop grand?) if (maxrate>0) { int r = (int) (new_stat_bytes/(time_local()-stat_timestart)); // taux actuel de transfert HTS_STAT.HTS_TOTAL_RECV_STATE=0; if (r>maxrate) { // taux>taux autorisΘ int taux = (int) (((double) (r - maxrate) * 100) / (double) maxrate); if (taux<15) HTS_STAT.HTS_TOTAL_RECV_STATE=1; // ralentir un peu (<15% dΘpassement) else if (taux<50) HTS_STAT.HTS_TOTAL_RECV_STATE=2; // beaucoup (<50% dΘpassement) else HTS_STAT.HTS_TOTAL_RECV_STATE=3; // ΘnormΘment (>50% dΘpassement) } } } // --- // sous routines liΘes au moteur et au backing // supplemental links ready (done) after ptr int backlinks_done(lien_url** liens,int lien_tot,int ptr) { int n=0; int i; //Links done and stored in cache for(i=ptr+1;i<lien_tot;i++) { if (liens[i]) { if (liens[i]->pass2 == -1) { n++; } } } return n; } // remplir backing si moins de max_bytes en mΘmoire HTS_INLINE int back_fillmax(lien_back* back,int back_max,httrackp* opt,cache_back* cache,lien_url** liens,int ptr,int numero_passe,int lien_tot) { if (back_incache(back,back_max)<opt->maxcache) { // pas trop en mΘmoire? return back_fill(back,back_max,opt,cache,liens,ptr,numero_passe,lien_tot); } return -1; /* plus de place */ } // remplir backing int back_fill(lien_back* back,int back_max,httrackp* opt,cache_back* cache,lien_url** liens,int ptr,int numero_passe,int lien_tot) { int n; // ajouter autant de socket qu'on peut ajouter n=opt->maxsoc-back_nsoc(back,back_max); // vΘrifier qu'il restera assez de place pour les tests ensuite (en thΘorie, 1 entrΘe libre restante suffirait) n=min( n, back_available(back,back_max) - 8 ); // no space left on backing stack - do not back anymore if (back_stack_available(back,back_max) <= 2) n=0; if (n>0) { int p; if (ptr<cache->ptr_last) { /* restart (2 scans: first html, then non html) */ cache->ptr_ant=0; } p=ptr+1; /* on a dΘja parcouru */ if (p<cache->ptr_ant) p=cache->ptr_ant; while( (p<lien_tot) && (n>0) ) { //while((p<lien_tot) && (n>0) && (p < ptr+opt->maxcache_anticipate)) { int ok=1; // on ne met pas le fichier en backing si il doit Ωtre traitΘ aprΦs if (liens[p]->pass2) { // 2Φ passe if (numero_passe!=1) ok=0; } else { if (numero_passe!=0) ok=0; } // note: si un backing est fini, il reste en mΘmoire jusqu'α ce que // le ptr l'atteigne if (ok) { if (!back_exist(back,back_max,liens[p]->adr,liens[p]->fil,liens[p]->sav)) { if (back_add(back,back_max,opt,cache,liens[p]->adr,liens[p]->fil,liens[p]->sav,liens[liens[p]->precedent]->adr,liens[liens[p]->precedent]->fil,liens[p]->testmode,&liens[p]->pass2)==-1) { if ( (opt->debug>1) && (opt->errlog!=NULL) ) { fspc(opt->errlog,"debug"); fprintf(opt->errlog,"error: unable to add more links through back_add for back_fill"LF); test_flush; } #if BDEBUG==1 printf("error while adding\n"); #endif n=0; // sortir } else { n--; #if BDEBUG==1 printf("backing: %s%s\n",liens[p]->adr,liens[p]->fil); #endif } } } p++; } // while /* sauver position derniΦre anticipation */ cache->ptr_ant=p; cache->ptr_last=ptr; } return 0; } // --- // routines de dΘtournement de SIGHUP & co (Unix) void sig_finish( int code ) { // finir et quitter signal(code,sig_term); // quitter si encore exit_xh=1; printf("\nExit requested to engine (signal %d)\n",code); } void sig_term( int code ) { // quitter brutalement printf("\nProgram terminated (signal %d)\n",code); exit(0); } #if HTS_WIN void sig_ask( int code ) { // demander static char s[256]; signal(code,sig_term); // quitter si encore printf("\nQuit program/Cancel? (Q/C) "); fflush(stdout); scanf("%s",s); if ( (s[0]=='y') || (s[0]=='Y') || (s[0]=='o') || (s[0]=='O') || (s[0]=='q') || (s[0]=='Q')) exit(0); // quitter signal(code,sig_ask); // remettre signal } #else void sig_back( int code ) { // ignorer et mettre en backing signal(code,sig_ignore); sig_doback(0); } void sig_ask( int code ) { // demander static char s[256]; signal(code,sig_term); // quitter si encore printf("\nQuit program/Background/bLind background/Cancel? (Q/B/L/C) "); fflush(stdout); scanf("%s",s); if ( (s[0]=='y') || (s[0]=='Y') || (s[0]=='o') || (s[0]=='O') || (s[0]=='q') || (s[0]=='Q')) exit(0); // quitter else if ( (s[0]=='b') || (s[0]=='B') || (s[0]=='a') || (s[0]=='A') ) sig_doback(0); // arriΦre plan else if ( (s[0]=='l') || (s[0]=='L') ) sig_doback(1); // arriΦre plan else { printf("cancel..\n"); signal(code,sig_ask); // remettre signal } } void sig_ignore( int code ) { // ignorer signal // // signal(code,sig_ignore); } void sig_doback(int blind) { // mettre en backing int out=-1; // printf("\nMoving to background to complete the mirror...\n"); fflush(stdout); if (!blind) out = open("hts-nohup.out",O_CREAT|O_WRONLY,S_IRUSR|S_IWUSR); if (out == -1) out = open("/dev/null",O_WRONLY,S_IRUSR|S_IWUSR); close(0); close(1); dup(out); close(2); dup(out); // switch (fork()) { case 0: break; case -1: printf("Error: can not fork process\n"); break; default: // pere usleep(100000); // pause 1/10s "A microsecond is .000001s" _exit(0); break; } } #endif // fin routines de dΘtournement de SIGHUP & co // Poll stdin.. si besoin #if HTS_POLL // lecture stdin des caractΦres disponibles int read_stdin(char* s,int max) { int i=0; while((check_stdin()) && (i<(max-1)) ) s[i++]=fgetc(stdin); s[i]='\0'; return i; } #ifdef _WIN32 HTS_INLINE int check_stdin() { return (_kbhit()); } #else HTS_INLINE int check_flot(T_SOC s) { fd_set fds; struct timeval tv; FD_ZERO(&fds); FD_SET((T_SOC) s,&fds); tv.tv_sec=0; tv.tv_usec=0; select(s+1,&fds,NULL,NULL,&tv); return FD_ISSET(s,&fds); } HTS_INLINE int check_stdin() { fflush(stdout); fflush(stdin); if (check_flot(0)) return 1; return 0; } #endif #endif // Attente de touche #if HTS_ANALYSTE!=2 int ask_continue() { char s[12]=""; printf("Press <Y><Enter> to confirm, <N><Enter> to abort\n"); io_flush; linput(stdin,s,4); if (strnotempty(s)) { if ((strfield2(s,"N")) || (strfield2(s,"NO")) || (strfield2(s,"NON"))) return 0; } return 1; } #else int ask_continue() { char* s; s=hts_htmlcheck_query2(HTbuff); if (s) { if (strnotempty(s)) { if ((strfield2(s,"N")) || (strfield2(s,"NO")) || (strfield2(s,"NON"))) return 0; } return 1; } return 1; } #endif // nombre de digits dans un nombre int nombre_digit(int n) { register int i=1; while(n >= 10) { n/=10; i++; } return i; } // renvoi adresse de la fin du token dans p // renvoi NULL si la chaine est un token unique // (PATCHE Θgalement la chaine) // ex: "test" "test2" renvoi adresse sur espace // flag==1 si chaine comporte des echappements comme \" char* next_token(char* p,int flag) { int detect=0; int quote=0; p--; do { p++; if (flag && (*p=='\\')) { // sauter \x ou \" if (quote) { char c='\0'; if (*(p+1)=='\\') c='\\'; else if (*(p+1)=='"') c='"'; if (c) { char tempo[8192]; tempo[0]=c; tempo[1]='\0'; strcat(tempo,p+2); strcpy(p,tempo); } } } else if (*p==34) { // guillemets (de fin) quote=!quote; } else if (*p==32) { if (!quote) detect=1; } else if (*p=='\0') { p=NULL; detect=1; } } while(!detect); return p; } // routines annexes #if HTS_ANALYSTE==2 // canceller un fichier (noter comme cancellable) char* hts_cancel_file(char * s) { static char sav[HTS_URLMAXSIZE*2]=""; if (s[0]!='\0') if (sav[0]=='\0') strcpy(sav,s); return sav; } void hts_cancel_test() { if (_hts_in_html_parsing==2) _hts_cancel=2; } void hts_cancel_parsing() { if (_hts_in_html_parsing) _hts_cancel=1; } #endif // for(_i=0;(_i<back_max) && (index<NFICH);_i++) { // i=(back_index+_i)%back_max; // commencer par le "premier" (l'actuel) // if (back[i].status>=0) { // signifie "lien actif" /* hts_add_file, add/get elements in the add chain for java parsing if file_position >= 0 push 'file/file_position' return 1 (return 0 if exists) else pop file -> 'file' return 'file_position' else if empty/error return -1; */ typedef struct addfile_chain { char name[1024]; int pos; struct addfile_chain* next; } addfile_chain; int hts_add_file(char* file,int file_position) { static struct addfile_chain* chain=NULL; if (file_position>=0) { /* copy file to the chain */ struct addfile_chain** current; current=&chain; /* start from */ while(*current) { if (strcmp((*current)->name,file)==0) return 0; /* already exists */ current=&( (*current)->next ); /* 'next' address */ } *current=calloc(1,sizeof(addfile_chain)); if (*current) { (*current)->next=NULL; (*current)->pos=-1; (*current)->name[0]='\0'; } if (*current) { strcpy((*current)->name,file); (*current)->pos=file_position; return 1; } else { printf("PANIC! Too many Java files during parsing [1]\n"); return -1; } } else { /* copy last element in file and delete it */ if (file) file[0]='\0'; if (chain) { struct addfile_chain** current; int pos=-1; current=&chain; /* start from */ while( (*current)->next ) { current=&( (*current)->next ); /* 'next' address */ } if (file) strcpy(file,(*current)->name); pos=(*current)->pos; free(*current); *current=NULL; return pos; } return -1; /* no more elements */ } /* static char* buffer; if (strlen(file)==8) { if (file[0]=='$') { // commande if (strcmp(file,"$BUFFER$")==0) { // indiquer adresse buffer! buffer=file; // le buffer buffer[0]='\0'; return 1; } } } if (strlen(buffer)<32000) { // vΘrifier.. strcat(buffer,file); strcat(buffer,"&"); // sΘparateur } else { printf("PANIC! Too many Java files during parsing [1]\n"); // ** buffer[32000]='\0'; // couper } */ return 0; } #if HTS_ANALYSTE==2 // en train de parser un fichier html? rΘponse: % effectuΘs // flag>0 : refresh demandΘ int hts_is_parsing(int flag) { if (_hts_in_html_parsing) { // parsing? if (flag>=0) _hts_in_html_poll=1; // faudrait un tit refresh return max(_hts_in_html_done,1); // % effectuΘs } else { return 0; // non } } int hts_is_testing() { // 0 non 1 test 2 purge if (_hts_in_html_parsing==2) return 1; else if (_hts_in_html_parsing==3) return 2; return 0; } // message d'erreur? char* hts_errmsg() { return _hts_errmsg; } // mode pause transfer int hts_setpause(int p) { if (p>=0) _hts_setpause=p; return _hts_setpause; } // rΘgler en cours de route les paramΦtres rΘglables.. // -1 : erreur int hts_setopt(httrackp* opt) { if (opt) _hts_setopt=opt; return 0; } // ajout d'URL // -1 : erreur int hts_addurl(char** url) { if (url) _hts_addurl=url; return (_hts_addurl!=NULL); } int hts_resetaddurl() { _hts_addurl=NULL; return (_hts_addurl!=NULL); } // copier nouveaux paramΦtres si besoin int copy_htsopt(httrackp* from,httrackp* to) { if (from->maxsite > -1) to->maxsite = from->maxsite; if (from->maxfile_nonhtml > -1) to->maxfile_nonhtml = from->maxfile_nonhtml; if (from->maxfile_html > -1) to->maxfile_html = from->maxfile_html; if (from->maxsoc > 0) to->maxsoc = from->maxsoc; if (from->nearlink > -1) to->nearlink = from->nearlink; if (from->timeout > -1) to->timeout = from->timeout; if (from->rateout > -1) to->rateout = from->rateout; if (from->maxtime > -1) to->maxtime = from->maxtime; if (from->maxrate > -1) to->maxrate = from->maxrate; if (strnotempty(from->user_agent)) strcpy(to->user_agent , from->user_agent); if (from->retry > -1) to->retry = from->retry; if (from->hostcontrol > -1) to->hostcontrol = from->hostcontrol; if (from->errpage > -1) to->errpage = from->errpage; if (from->parseall > -1) to->parseall = from->parseall; // test all: bit 8 de travel if (from->travel > -1) { if (from->travel & 256) to->travel|=256; else to->travel&=255; } return 0; } #endif // // message copyright interne void voidf(void) { char* a; a=""CRLF""CRLF; a="+-----------------------------------------------+"CRLF; a="|HyperTextTRACKer, Offline Browser Utility |"CRLF; a="| HTTrack Website Copier |"CRLF; a="|Code: Windows Interface Xavier Roche |"CRLF; a="| HTS/HTTrack Xavier Roche |"CRLF; a="| .class Parser Yann Philippot |"CRLF; a="| |"CRLF; a="|Tested on: Windows95,98,NT,2K |"CRLF; a="| Linux PC |"CRLF; a="| Sun-Solaris 5.6 |"CRLF; a="| AIX 4 |"CRLF; a="| |"CRLF; a="|Copyright (C) Xavier Roche and others |"CRLF; a="|Brought to you by Serianet, Caen, France |"CRLF; a="| |"CRLF; a="|Use this program at your own risks! |"CRLF; a="+-----------------------------------------------+"CRLF; a=""CRLF; } // HTTrack Website Copier Copyright (C) Xavier Roche and other contributors //